AngularJs未加载外部资源

198
使用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):/);

我看到这篇关于跨域问题的帖子,但我不确定如何解决这个问题或者应该采取什么方向。有什么想法吗?任何帮助都将不胜感激。


1
你能否也发布一下你的Cordova的config.xml文件? - Andrew Shustariov
1
现在我还在浏览器中进行测试,所以我甚至还没有开始我的PhoneGap调试。 - mhartington
9个回答

271

另一个简单的解决方案是创建一个过滤器:

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

然后在ng-src中指定过滤器:

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

23
绝对是最优雅和角度分明的解决方案。 - Sc0ttyD
1
对我来说很有效,而且确实比使用iframe更好。 - Thomas Amar
1
最佳答案,更加灵活的思路,并且在其他解决方案无法解决的情况下起作用。非常感谢! - floribon

270

这是唯一对我有效的解决方案:

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"};
});

然后在一个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


这是否可以在没有 iFrame 的情况下实现?我需要嵌入一个视频,会话信息确定消费者是否有权查看该视频。会话信息不通过 iFrame 传递。 - Blake
很好,如果您能使用 iframe。 - Ringo

77

使用$sceDelegateProvider将资源加入白名单

这是由Angular 1.2中实施的新安全策略引起的。它通过防止黑客发出外部请求(即向可能包含有效负载的外部URL发出请求)来增加了XSS攻击的难度。

为了正确解决此问题,您需要像以下示例代码一样将要允许的域名加入白名单:

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**'
  ]);
});

这个例子摘自文档,您可以在此处阅读:

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

请确保在您的应用程序中包含ngSanitize以使其正常工作。

禁用特性

如果您想要关闭此有用的功能,并且确定您的数据是安全的,您可以简单地允许 **,像这样:

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

2
注意:如果 resourceUrlWhitelist 对您不起作用,请检查您的域名后面是否有双斜杠(当从变量连接内容时,两个变量都有斜杠时很容易发生这种情况)。 - jakub.g
2
这是一个更干净、全局和安全的解决方法。 - DJ.
“拨出电话”不是一个很好的术语,用于帮助某人理解问题。 - Ringo
1
感谢@Ringo-我已经添加了一条评论来澄清。 - superluminary

21

我这里也遇到了同样的问题,我需要绑定Youtube链接。对我而言,作为一种全局解决方案,以下配置项有效:

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

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

}]);

在那里添加'self'非常重要-否则将无法绑定到任何URL。 来自angular文档

'self' - 特殊字符串'self'可用于匹配与应用程序文档相同协议的同一域中的所有URL。

有了这个设置,我现在能够直接绑定到任何Youtube链接。

显然,您需要根据自己的需求自定义正则表达式。希望它有所帮助!


4
最好且简单的解决此问题的方法是在控制器中从此函数传递您的数据。
$scope.trustSrcurl = function(data) 
{
    return $sce.trustAsResourceUrl(data);
}

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

2
如果有人在寻找TypeScript解决方案: .ts文件(根据需要更改变量):
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>

2

我在使用Videogular时遇到了同样的问题。当我使用ng-src时,我得到了以下信息:

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

我通过编写一个基本的指令来解决了这个问题:

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

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>

1
根据错误信息,您的问题似乎与插值(通常是您的表达式{{}})有关,而不是跨域问题。基本上,ng-src="{{object.src}}"不太好用。
我认为ng-src是针对img标签设计的,可能不适合。请参见http://docs.angularjs.org/api/ng.directive:ngSrc 如果您声明,它会正常工作,对吧?(请注意,我删除了ng-src以使用src)如果不行,必须先修复它。
然后确保{{object.src}}返回预期值(在

仅使用src并硬编码URL,一切都按照我的意愿工作。但是,一旦我使用{{object.src}},src属性甚至没有被传递。我甚至去掉了source标签,并将src内联到video标签中,但仍然没有任何反应。 - mhartington
{{object.src}}正在返回一个值。通过使用<p></p>和<a></a>进行测试。 - mhartington
还有另一种选择:使用指令。 - roland
1
可能需要,我已经找到了这个网站,看起来非常不错。http://www.videogular.com/#/。感谢您的帮助。 - mhartington
2
这与 ng-src 出现故障无关(它没有出现故障)。这与 AngularJS 的安全策略有关:http://docs.angularjs.org/api/ng/service/$sce - Pauan
显示剩余2条评论

0

我在测试中遇到了这个错误,指令templateUrl没有被信任,但只是针对规范,所以我添加了模板目录:

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

我的主目录是app


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接