Recurso externo não sendo carregado por AngularJs

195

Usando Angular e Phonegap, estou tentando carregar um vídeo que esteja em um servidor remoto, mas que deparei com um problema. No meu JSON, o URL é inserido como um URL HTTP simples.

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

Meu modelo de vídeo

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

Todos os meus outros dados são carregados, mas quando olho para o console, recebo este erro:

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

Tentei adicionar $compileProviderminha configuração, mas ela não resolveu meu problema.

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

Vi este post sobre problemas entre domínios, mas não sei como resolver isso ou em que direção devo seguir. Alguma idéia? Qualquer ajuda é apreciada

Mhartington
fonte
1
Você também pode postar o config.xmlarquivo do seu corodva ?
Andrew Shustariov
1
No momento, ainda estou testando no navegador, então nem iniciei a depuração do grampo telefônico.
precisa saber é o seguinte

Respostas:

267

Esta é a única solução que funcionou para mim:

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

Em seguida, em um 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

Guy Sopher
fonte
Isso é possível sem um iFrame? Preciso incorporar um vídeo em que as informações da sessão determinem se o consumidor pode ou não ver o vídeo. As informações da sessão não são transportadas pelo iFrame.
Blake
bom, se você pode usar iframe
Ringo
270

Outra solução simples é criar um filtro:

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

Em seguida, especifique o filtro em ng-src:

<video controls poster="img/poster.png">
       <source ng-src="{{object.src | trusted}}" type="video/mp4"/>
</video>
David Boyd
fonte
22
Definitivamente a solução mais elegante e angular.
Sc0ttyD
1
Funcionou para mim e, de fato, é melhor do que usar um iframe.
Thomas Amar
1
Melhor resposta, espírito mais angular e funcionou onde as outras soluções não funcionaram por alguns motivos. Muito obrigado!
Floribon 15/10
76

Lista de permissões o recurso com $ sceDelegateProvider

Isso é causado por uma nova política de segurança implementada no Angular 1.2. Isso torna o XSS mais difícil, impedindo que um hacker faça discagem (ou seja, faça uma solicitação para uma URL estrangeira, potencialmente contendo uma carga útil).

Para contorná-lo corretamente, você precisa colocar na lista de permissões os domínios que deseja permitir, assim:

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

Este exemplo é retirado da documentação que você pode ler aqui:

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

Certifique-se de incluir ngSanitize no seu aplicativo para fazer isso funcionar.

Desativando o recurso

Se você deseja desativar esse recurso útil e tem certeza de que seus dados estão seguros, basta permitir **, da seguinte forma:

angular.module('app').config(function($sceDelegateProvider) {
  $sceDelegateProvider.resourceUrlWhitelist(['**']);
});
superluminário
fonte
2
Nota: se resourceUrlWhitelistalguma forma não funciona para você, verifique se você não tem barra dupla depois de nome de domínio (fácil para que isso aconteça quando concatenando coisas de variáveis e ambos têm barras)
jakub.g
2
Essa é uma maneira mais limpa, global e segura de solucionar esse problema.
DJ.
"Discar" não é um ótimo termo para quem tenta entender o problema.
Ringo
1
Obrigado @Ringo - Adicionei um comentário para esclarecer.
superluminary
21

Teve o mesmo problema aqui. Eu precisava ligar para os links do Youtube. O que funcionou para mim, como solução global , foi adicionar o seguinte à minha configuração:

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

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

}]);

Adicionar 'self' é importante; caso contrário, não será possível vincular a qualquer URL. Dos documentos angulares

'self' - A cadeia especial, 'self', pode ser usada para corresponder a todos os URLs do mesmo domínio que o documento do aplicativo usando o mesmo protocolo.

Com isso, agora posso vincular diretamente a qualquer link do YouTube.

Obviamente, você precisará personalizar o regex de acordo com suas necessidades. Espero que ajude!

zumek
fonte
4

A melhor e mais fácil solução para solucionar esse problema é passar seus dados dessa função no controlador.

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

Na página html

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

Encontrei o mesmo problema usando o Videogular. Eu estava recebendo o seguinte ao usar ng-src:

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

Corrigi o problema escrevendo uma diretiva básica:

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

O 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>
cagan
fonte
2

Se alguém estiver procurando por uma solução TypeScript:

Arquivo .ts (altere variáveis, quando aplicável):

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>
GONeale
fonte
1

Com base na mensagem de erro, seu problema parece estar relacionado à interpolação (normalmente sua expressão {{}}), não a um problema entre domínios. É basicamente uma ng-src="{{object.src}}"merda.

ng-srcfoi projetado com a imgtag IMO em mente. Pode não ser apropriado para <source>. Veja http://docs.angularjs.org/api/ng.directive:ngSrc

Se você declarar <source src="somesite.com/myvideo.mp4"; type="video/mp4"/>, estará funcionando, certo? (note que eu removo a ng-srcfavor de src) Se não, deve ser corrigido primeiro.

Em seguida, verifique se {{object.src}}retorna o valor esperado ( fora de <video>):

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

Se retornar o valor esperado, a seguinte instrução deverá estar funcionando:

<source src="{{object.src}}"; type="video/mp4"/> //src instead of ng-src
Roland
fonte
Usando apenas src e codificando o URL, tudo funciona como eu quero. Assim que eu uso o {{object.src}}, embora o atributo src nem seja passado no pensamento. Fui em frente e até removi a tag de origem e coloquei o src em linha com a tag de vídeo, mas ainda nada
mhartington
Quero dizer, você tem certeza que {{object.src}} retorna um valor? Pode retornar indefinido.
Roland
{{object.src}} está retornando um valor. Testado usando um <p> </ p> e uma <a> </a>
mhartington
1
Provavelmente vai ter que, já encontrei isso e parece muito bom. videogular.com/# . Obrigado pela ajuda
mhartington
2
Isso não tem nada a ver com ng-srcser quebrado (não está quebrado). Tem a ver com a política de segurança do AngularJS: docs.angularjs.org/api/ng/service/$sce
Pauan
0

Eu tive esse erro nos testes , a diretiva templateUrlnão era confiável, mas apenas para as especificações, então adicionei o diretório do modelo:

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

Meu diretório principal é app.

ecológico
fonte