AngularJS未加载外部资源

使用Angular和PhoneGap,我正在尝试加载远程服务器上的视频,但遇到了一个问题。在我的JSON中,URL是作为普通的HTTP URL输入的。

"src" : "http://www.somesite.com/myvideo.mp4"

我的视频模板

 <video controls poster="img/poster.png">
<source ng-src="{{object.src}}" type="video/mp4"/>
</video>

我的所有其他数据都被加载,但当我查看我的控制台时,我得到这个错误:

Error: [$interpolate:interr] Can't interpolate: {{object.src}}
Error: [$sce:insecurl] Blocked loading resource from url not allowed by $sceDelegate policy.  URL

我尝试在我的配置设置中添加$compileProvider,但它没有解决我的问题。

$compileProvider.aHrefSanitizationWhitelist(/^\s*(https?|ftp|mailto|file|tel):/);

我看到了这篇关于跨域问题的文章S,但我不知道如何解决这个问题,或者我应该往哪个方向走。有什么想法吗?任何帮助都很感激。

128338 次浏览

Based on the error message, your problem seems to be related to interpolation (typically your expression \{\{}}), not to a cross-domain issue. Basically ng-src="\{\{object.src}}" sucks.

ng-src was designed with img tag in mind IMO. It might not be appropriate for <source>. See http://docs.angularjs.org/api/ng.directive:ngSrc

If you declare <source src="somesite.com/myvideo.mp4"; type="video/mp4"/>, it will be working, right? (note that I remove ng-src in favor of src) If not it must be fixed first.

Then ensure that \{\{object.src}} returns the expected value (outside of <video>):

<span>\{\{object.src}}</span>
<video>...</video>

If it returns the expected value, the following statement should be working:

<source src="\{\{object.src}}"; type="video/mp4"/> //src instead of ng-src

I ran into the same problem using Videogular. I was getting the following when using ng-src:

Error: [$interpolate:interr] Can't interpolate: \{\{url}}
Error: [$sce:insecurl] Blocked loading resource from url not allowed by $sceDelegate policy

I fixed the problem by writing a basic directive:

angular.module('app').directive('dynamicUrl', function () {
return {
restrict: 'A',
link: function postLink(scope, element, attrs) {
element.attr('src', scope.content.fullUrl);
}
};
});

The html:

 <div videogular vg-width="200" vg-height="300" vg-theme="config.theme">
<video class='videoPlayer' controls preload='none'>
<source dynamic-url src='' type='\{\{ content.mimeType }}'>
</video>
</div>

This is the only solution that worked for me:

var app = angular.module('plunker', ['ngSanitize']);


app.controller('MainCtrl', function($scope, $sce) {
$scope.trustSrc = function(src) {
return $sce.trustAsResourceUrl(src);
}


$scope.movie = {src:"http://www.youtube.com/embed/Lx7ycjC8qjE", title:"Egghead.io AngularJS Binding"};
});

Then in an iframe:

<iframe class="youtube-player" type="text/html" width="640" height="385"
ng-src="\{\{trustSrc(movie.src)}}" allowfullscreen frameborder="0">
</iframe>

http://plnkr.co/edit/tYq22VjwB10WmytQO9Pb?p=preview

Had the same issue here. I needed to bind to Youtube links. What worked for me, as a global solution, was to add the following to my config:

.config(['$routeProvider', '$sceDelegateProvider',
function ($routeProvider, $sceDelegateProvider) {


$sceDelegateProvider.resourceUrlWhitelist(['self', new RegExp('^(http[s]?):\/\/(w{3}.)?youtube\.com/.+$')]);


}]);

Adding 'self' in there is important - otherwise will fail to bind to any URL. From the angular docs

'self' - The special string, 'self', can be used to match against all URLs of the same domain as the application document using the same protocol.

With that in place, I'm now able to bind directly to any Youtube link.

You'll obviously have to customise the regex to your needs. Hope it helps!

Another simple solution is to create a filter:

app.filter('trusted', ['$sce', function ($sce) {
return function(url) {
return $sce.trustAsResourceUrl(url);
};
}]);

Then specify the filter in ng-src:

<video controls poster="img/poster.png">
<source ng-src="\{\{object.src | trusted}}" type="video/mp4"/>
</video>

Whitelist the resource with $sceDelegateProvider

This is caused by a new security policy put in place in Angular 1.2. It makes XSS harder by preventing a hacker from dialling out (i.e. making a request to a foreign URL, potentially containing a payload).

To get around it properly you need to whitelist the domains you want to allow, like this:

angular.module('myApp',['ngSanitize']).config(function($sceDelegateProvider) {
$sceDelegateProvider.resourceUrlWhitelist([
// Allow same origin resource loads.
'self',
// Allow loading from our assets domain.  Notice the difference between * and **.
'http://srv*.assets.example.com/**'
]);


// The blacklist overrides the whitelist so the open redirect here is blocked.
$sceDelegateProvider.resourceUrlBlacklist([
'http://myapp.example.com/clickThru**'
]);
});

This example is lifted from the documentation which you can read here:

https://docs.angularjs.org/api/ng/provider/$sceDelegateProvider

Be sure to include ngSanitize in your app to make this work.

Disabling the feature

If you want to turn off this useful feature, and you're sure your data is secure, you can simply allow **, like so:

angular.module('app').config(function($sceDelegateProvider) {
$sceDelegateProvider.resourceUrlWhitelist(['**']);
});

The best and easy solution for solving this issue is pass your data from this function in controller.

$scope.trustSrcurl = function(data)
{
return $sce.trustAsResourceUrl(data);
}

In html page

<iframe class="youtube-player" type="text/html" width="640" height="385" ng-src="\{\{trustSrcurl(video.src)}}" allowfullscreen frameborder="0"></iframe>

If anybody is looking for a TypeScript solution:

.ts file (change variables where applicable):

module App.Filters {


export class trustedResource {


static $inject:string[] = ['$sce'];


static filter($sce:ng.ISCEService) {
return (value) => {
return $sce.trustAsResourceUrl(value)
};
}
}
}
filters.filter('trustedResource', App.Filters.trusted.filter);

Html:

<video controls ng-if="HeaderVideoUrl != null">
<source ng-src="\{\{HeaderVideoUrl | trustedResource}}" type="video/mp4"/>
</video>

I had this error in tests, the directive templateUrl wasn't trusted, but only for the spec, so I added the template directory:

beforeEach(angular.mock.module('app.templates'));

My main directory is app.