Zasób zewnętrzny nie jest ładowany przez AngularJs

195

Korzystając z Angular i Phonegap, próbuję załadować wideo, które znajduje się na zdalnym serwerze, ale napotkałem problem. W moim JSON adres URL jest wprowadzany jako zwykły adres URL HTTP.

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

Mój szablon wideo

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

Wszystkie inne dane są ładowane, ale gdy patrzę na konsolę, pojawia się następujący błąd:

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

Próbowałem dodać $compileProviderw konfiguracji, ale to nie rozwiązało mojego problemu.

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

Widziałem ten post o problemach między domenami, ale nie jestem pewien, jak rozwiązać ten problem ani w jakim kierunku powinienem iść. Jakieś pomysły? Każda pomoc jest mile widziana

mhartington
źródło
1
Czy możesz również opublikować config.xmlplik swojej corodvy ?
Andrew Shustariov
1
W tej chwili wciąż testuję w przeglądarce, więc nawet nie rozpocząłem debugowania na telefonie.
mhartington

Odpowiedzi:

267

To jedyne rozwiązanie, które działało dla mnie:

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

Następnie w ramce 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
źródło
Czy to możliwe bez ramki iFrame? Muszę osadzić film, w którym informacje o sesji określają, czy konsument może go zobaczyć. Informacje o sesji nie są przenoszone przez ramkę iFrame.
Blake,
fajnie, jeśli możesz użyć iframe
Ringo,
270

Innym prostym rozwiązaniem jest utworzenie filtra:

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

Następnie określ filtr w ng-src:

<video controls poster="img/poster.png">
       <source ng-src="{{object.src | trusted}}" type="video/mp4"/>
</video>
David Boyd
źródło
22
Zdecydowanie najbardziej eleganckie i wyraziste rozwiązanie.
Sc0ttyD
1
Pracował dla mnie i rzeczywiście jest ładniejszy niż używanie iframe.
Thomas Amar
1
Najlepsza odpowiedź, bardziej ostry duch i zadziałało tam, gdzie inne rozwiązania nie działały z jakichś powodów. Wielkie dzięki!
floribon
76

Dodaj zasoby do białej listy za pomocą $ sceDelegateProvider

Jest to spowodowane nową polityką bezpieczeństwa wprowadzoną w Angular 1.2. Utrudnia to działanie XSS, uniemożliwiając hakerowi wybieranie numeru (tj. Wysłanie żądania na obcy adres URL, potencjalnie zawierający ładunek).

Aby obejść to poprawnie, musisz dodać do białej listy domen, na które chcesz zezwolić, w następujący sposób:

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

Ten przykład pochodzi z dokumentacji, którą możesz przeczytać tutaj:

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

Pamiętaj, aby dołączyć ngSanitize do swojej aplikacji, aby to działało.

Wyłączanie funkcji

Jeśli chcesz wyłączyć tę przydatną funkcję i masz pewność, że Twoje dane są bezpieczne, możesz po prostu pozwolić **, na przykład:

angular.module('app').config(function($sceDelegateProvider) {
  $sceDelegateProvider.resourceUrlWhitelist(['**']);
});
superluminarny
źródło
2
Uwaga: jeśli resourceUrlWhitelistjakoś nie działa, sprawdź, czy nie masz podwójnego ukośnika po nazwie domeny (łatwo to zrobić,
łącząc elementy
2
Jest to czystszy, globalny i bezpieczny sposób na obejście tego problemu.
DJ.
„Wybieranie numeru” nie jest dobrym terminem dla kogoś, kto próbuje zrozumieć problem.
Ringo,
1
Dzięki @Ringo - dodałem komentarz w celu wyjaśnienia.
superluminarny
21

Miałem ten sam problem tutaj. Musiałem powiązać linki do YouTube. Jako globalne rozwiązanie zadziałało dodanie do mojej konfiguracji następujących elementów:

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

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

}]);

Dodanie „self” jest tam ważne - w przeciwnym razie nie uda się powiązać z żadnym adresem URL. Z kątowych dokumentów

„self” - ciąg specjalny „self” można wykorzystać do dopasowania do wszystkich adresów URL tej samej domeny, co dokument aplikacji, przy użyciu tego samego protokołu.

Dzięki temu mogę teraz łączyć się bezpośrednio z dowolnym linkiem do YouTube.

Oczywiście będziesz musiał dostosować regex do swoich potrzeb. Mam nadzieję, że to pomoże!

zumek
źródło
4

Najlepszym i łatwym rozwiązaniem tego problemu jest przekazanie danych z tej funkcji do kontrolera.

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

Na stronie HTML

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

Ten sam problem napotkałem za pomocą Videogular. Podczas używania ng-src otrzymywałem następujące informacje:

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

Rozwiązałem problem, pisząc podstawową dyrektywę:

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>
Cagan
źródło
2

Jeśli ktoś szuka rozwiązania TypeScript:

plik .ts (w razie potrzeby zmień zmienne):

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
źródło
1

Na podstawie komunikatu o błędzie twój problem wydaje się być związany z interpolacją (zazwyczaj z twoim wyrażeniem {{}}), a nie z problemem między domenami. Zasadniczo ng-src="{{object.src}}"jest do bani.

ng-srczostał zaprojektowany z myślą o imgtagach IMO. Może to nie być odpowiednie <source>. Zobacz http://docs.angularjs.org/api/ng.directive:ngSrc

Jeśli zadeklarujesz <source src="somesite.com/myvideo.mp4"; type="video/mp4"/>, będzie działać, prawda? (zwróć uwagę, że usuwam ng-srcna korzyśćsrc ). Jeśli nie, najpierw trzeba to naprawić.

Następnie upewnij się, że {{object.src}}zwraca wartość oczekiwaną ( na zewnątrz od <video>):

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

Jeśli zwraca oczekiwaną wartość, powinna działać następująca instrukcja:

<source src="{{object.src}}"; type="video/mp4"/> //src instead of ng-src
roland
źródło
Używając tylko src i twardego kodowania adresu URL, wszystko działa tak, jak chcę. Jak tylko użyję {{object.src}}, chociaż atrybut src nie jest nawet brany pod uwagę. Poszedłem dalej, a nawet
usunąłem
Mam na myśli, czy jesteś pewien, że {{object.src}} zwraca wartość? Może zwrócić niezdefiniowany.
roland
{{object.src}} zwraca wartość. Przetestowałem to, używając <p> </p> i <a> </a>
mhartington
1
Prawdopodobnie będzie musiał to już znaleźć i wygląda całkiem nieźle. videogular.com/# . Dzięki za pomoc
mhartington
2
Nie ma to nic wspólnego z ng-srcbyciem zepsutym (nie jest zepsute). Ma to związek z polityką bezpieczeństwa AngularJS: docs.quarejs.org/api/ng/service/$sce
Pauan
0

Miałem ten błąd w testach , dyrektywa templateUrlnie była zaufana, ale tylko dla specyfikacji, więc dodałem katalog szablonów:

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

Mój główny katalog to app.

ekologiczny
źródło