Зовнішній ресурс не завантажується AngularJs


195

Використовуючи Angular та Phonegap, я намагаюся завантажити відео, яке знаходиться на віддаленому сервері, але зіткнулося з проблемою. У моєму JSON URL вводиться як звичайна HTTP-адреса.

"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
Чи можете ви також опублікувати config.xmlфайл вашого corodva ?
— Андрій Шустарьов

1
Зараз я все ще тестую браузер, так що я навіть не запускав налагодження фонегапу.
— mhartington

Відповіді:


267

Це єдине рішення, яке працювало для мене:

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 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.
— Блейк

приємно, якщо ви можете використовувати iframe
— Ringo

270

Ще одне просте рішення - створити фільтр:

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>

22
Однозначно найелегантніше та найпотужніше рішення.
— Sc0ttyD

1
Працювало для мене, і справді це приємніше, ніж використовувати рамку.
— Томас Амар

1
Найкраща відповідь, більш кутовий дух, і він працював там, де інші рішення чомусь не зробили. Дуже дякую!
— floribon

76

Білий список ресурсу за допомогою $ sceDelegateProvider

Це спричинено новою політикою безпеки, введеною у Angular 1.2. Це ускладнює XSS, не дозволяючи хакеру набрати номер (тобто зробити запит на іноземну URL-адресу, що потенційно містить корисний навантаження).

Щоб правильно їх обійти, потрібно додати білий список доменів, які ви хочете дозволити, наприклад:

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якимось чином не працює для вас, перевірте, чи немає у вас подвійної косої риски після доменного імені (легко це може статися при об'єднанні речей із змінних, і вони обоє мають косу
— рису

2
Це більш чистий, глобальний та безпечний спосіб вирішити цю проблему.
— діджей.

"Набір номера" - не чудовий термін, який можна використовувати для тих, хто намагається зрозуміти проблему.
— Рінго

1
Дякую @Ringo - я додав коментар для уточнення.
— суперлюмінація

21

Тут було те саме питання Мені потрібно було прив’язати посилання на Youtube. Що для мене, як глобальне рішення , було додати наступне:

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

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

}]);

Додавання "self" туди є важливим - інакше не вдасться прив’язати до будь-якої URL-адреси. З кутових док

'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

Я зіткнувся з тією ж проблемою, використовуючи 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>

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>

1

Виходячи з повідомлення про помилку, ваша проблема, схоже, пов’язана з інтерполяцією (як правило, з вашим вираженням {{}}), а не з проблемою міждоменного зв’язку. В основному ng-src="{{object.src}}"смокче.

ng-srcбув розроблений з imgтегом на увазі IMO. Це може бути не підходящим для <source>. Див. Http://docs.angularjs.org/api/ng.directive:ngSrc

Якщо ви заявите <source src="somesite.com/myvideo.mp4"; type="video/mp4"/>, це буде спрацьовує, правда? (зауважте, я знімаю ng-srcна користь src) Якщо це не так, його потрібно виправити спочатку.

Потім переконайтеся , що {{object.src}}повертає очікуване значення ( за межами від <video>):

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

Якщо воно поверне очікуване значення, наступне твердження має працювати:

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

Використовуючи лише src та жорстке кодування URL-адреси, все працює так, як я хочу. Як тільки я використовую {{object.src}}, хоча атрибут src навіть не замислюється. Я пішов вперед і навіть видалив вихідний тег і поставив src в
— рядок із відеотегом,

Тобто ти впевнений, що {{object.src}} повертає значення? Це може повернутися невизначено.
— roland

{{object.src}} повертає значення. Випробували його, використовуючи <p> </p> та <a> </a>
— mhartington

1
Напевно, доведеться це вже знайти, і це виглядає досить непогано. videogular.com/# . Дякую за допомогу
— mhartington

2
Це не має нічого спільного з ng-srcтим, щоб бути зламаним (він не порушений). Це стосується політики безпеки AngularJS: docs.angularjs.org/api/ng/service/$sce
— Pauan

0

У мене була помилка в тестах , директиві templateUrlне довіряли, а лише специфікації, тому я додав каталог шаблонів:

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

Головний мій каталог app.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.