The unsafe resource URL and cross origin on angular

在angular很常遇到compile template時出錯的情況,因為在angular中,使用比較嚴謹的判斷方式,只要看到不符合規範,會直接拋出exception

##Cross origin

以下是一個video的範例,設定影片的source:

1
2
3
<video width="320" height="240" controls>
<source src="{{source}}" type="video/mp4">
</video>

設定source的影片來源:

1
$scope.source = "http://other.sparrowhome.twbbs.org/movie.mp4"

這時就會發現angular拋出exception,出現cross domain的問題。

但是若是直接寫在html上呢?

1
2
3
<video width="320" height="240" controls>
<source src="http://other.sparrowhome.twbbs.org/movie.mp4" type="video/mp4">
</video>

此時你可以發現能正常的播放,但是在angular就是會拋錯,這時你可以透過$sceDelegateProvider,來設定黑名單白名單,決定哪個domain可以讀取這隻影片。

假設你要讓所有domain都能使用,在白名單可以這樣寫:

1
2
3
4
5
angular
.module('MyApp')
.config(['$sceDelegateProvider', function($sceDelegateProvider) {
$sceDelegateProvider.resourceUrlWhitelist(['**']);
})

若是你只要目前網域底下的子網域都可以讀取的話,可以這樣寫:

1
$sceDelegateProvider.resourceUrlWhitelist(['http://*.sparrowhome.twbbs.org'])

如果要透過黑名單可以直接使用resourceUrlBlacklist

##Unsafe resource URL

如果是讀取img,不管是cross domain都能正常讀取,不過還是會有不讀取的狀況。

例如你透過一個<input type="file">,去取得顯示image,像是<img ng-src="{{img}}" />

1
$scope.img = URL.createObjectURL(imgFile);

此時就會拋出unsafe:blobexception,依據URL.createObjectURL所取得url,可以很容易發現,最前方協定是不同的。例如URL.createObjectURL回傳一個blob:http%3A%2F%2Fsparrowhome.twbbs.org%2Fimage.png,此時不在預設的允許名單中,這時就要透過$compileProvider.imgSrcSanitizationWhitelist去改寫。

像是讓所有協定都通過:

1
2
3
4
angular.module('MyApp').config(['$sceDelegateProvider', function( $compileProvider ) {

$compileProvider.imgSrcSanitizationWhitelist(/^.*/);
}

也可自訂要通過特定的協定,像是/^(https?|ftp|file|blob|data):/,同樣的href也有aHrefSanitizationWhitelist可以去設定。在angular中使用要嚴謹的判斷方式,當然也可透過jquery或原生javascript繞過這問題,不過這樣就有點失去用angular的意義了,畢竟用template的方式,比起寫code跟為簡潔。