Як увімкнути CORS у AngularJs


147

Я створив демонстрацію за допомогою JavaScript для API пошуку фотографій Flickr. Тепер я перетворюю це на AngularJs. Я шукав в Інтернеті і знайшов конфігурацію нижче.

Конфігурація:

myApp.config(function($httpProvider) {
  $httpProvider.defaults.useXDomain = true;
  delete $httpProvider.defaults.headers.common['X-Requested-With'];
});

Сервіс:

myApp.service('dataService', function($http) {
    delete $http.defaults.headers.common['X-Requested-With'];
    this.flickrPhotoSearch = function() {
        return $http({
            method: 'GET',
            url: 'http://api.flickr.com/services/rest/?method=flickr.photos.search&api_key=3f807259749363aaa29c76012fa93945&tags=india&format=json&callback=?',
            dataType: 'jsonp',
            headers: {'Authorization': 'Token token=xxxxYYYYZzzz'}
         });
     }
});

Контролер:

myApp.controller('flickrController', function($scope, dataService) {
        $scope.data = null;
        dataService.flickrPhotoSearch().then(function(dataResponse) {
            $scope.data = dataResponse;
            console.log($scope.data);
        });
    });

Але все-таки я отримав ту саму помилку. Ось декілька посилань, які я спробував:

XMLHttpRequest не може завантажити URL-адресу. Походження заборонено системою Access-Control-Allow-Origin

http://goo.gl/JuS5B1


1
Ви повинні запитувати дані у вашого проксі, ви все ще вимагаєте їх безпосередньо від flickr.
Квентін

@quentin Дякую за швидку відповідь. Чи можете ви мені, будь ласка, продемонструйте демонстрацію.
ankitr

1
Ви просто поміняєте URL з flickr.com на URL вашого проксі
Квентін,

1
Але як я буду називати flickr? як мені потрібні зображення з flickr.
ankitr

2
Клієнт викликає проксі. Проксі викликає flickr. Ось що означає проксі. (Ваш проксі-код ... не проксі, це веб-сервер для обслуговування JSON та JSONP зі статичних файлів).
Квентін

Відповіді:


193

Ви цього не робите. Сервер, на який ви звертаєтесь із запитом, повинен впровадити CORS для надання JavaScript доступу до вашого веб-сайту. Ваш JavaScript не може надати собі дозвіл на доступ до іншого веб-сайту.


1
Робіть запити на Flickr замість вашого сервера.
Квентін

Я не використовую сервер, але можу використовувати node.js. Чи можете ви мені показати шлях із цим?
анкітр

1
Не в просторі, доступному для коментаря. Це досить великий набір тем.
Квентін

Чому це , що я можу отримати відповідь від https://www.google.comвикористання програми , як POSTMAN, але коли я намагаюся GETз https://www.google.comдопомогою виклику AJAX я отримую помилку CORS? Чи немає способу змусити дзвінок AJAX поводитись так само, як дзвінок від POSTMAN?
AjaxLeung

5
@AlexLeung - Postman - це встановлена ​​програма. Якщо ваш веб-сайт може змусити мій браузер запитувати дані від Google і читати їх, то ваш веб-сайт може запитувати мою сторінку вхідних повідомлень GMail і читати всю мою електронну пошту. Це було б жахливо.
Квентін

64

У мене була подібна проблема, і для мене вона зводилася до додавання наступних заголовків HTTP у відповідь на кінець прийому :

Access-Control-Allow-Headers: Content-Type
Access-Control-Allow-Methods: GET, POST, OPTIONS
Access-Control-Allow-Origin: *

Ви можете віддати перевагу не використовувати *в кінці, а лише доменне ім'я хоста, що надсилає дані. Подібно до*.example.com

Але це можливо лише тоді, коли у вас є доступ до конфігурації сервера.


2
Я новачок у AngularJs. Скажіть, будь ласка, куди це здійснити?
ankitr

17
@Ankit Ці заголовки потрібно додати на сервері , а не в AngularJS.
Феліпе

2
@techcraver - Вам не потрібен оперативний доступ до конфігурації сервера - просто передайте заголовки зсередини сценарію. Якщо у вас є бекенд PHP, це було бheader('Access-Control-Allow-Origin: *');
davidkonrad

@davidkonrad: Я створив весь додаток у кутовій версії 4. Чи можете ви сказати, куди я повинен включити цей заголовок: /
Pygirl

@Pygirl, я вважаю, ти зробив клієнтську сторону в кутовому? Потрібно додати заголовки на сторону сервера відповідей, як і де залежать від технології. Якщо це скрипт PHP, який ви викликаєте з кутового Http.get()або подібного, додайте header('Access-Control-Allow-Origin: *')як перший вихід у виклику скрипта PHP (тобто перед тим, як вивести фактичну відповідь, JSON, що коли-небудь.
davidkonrad

9

Спробуйте скористатися службою ресурсів для споживання flickr jsonp:

var MyApp = angular.module('MyApp', ['ng', 'ngResource']);

MyApp.factory('flickrPhotos', function ($resource) {
    return $resource('http://api.flickr.com/services/feeds/photos_public.gne', { format: 'json', jsoncallback: 'JSON_CALLBACK' }, { 'load': { 'method': 'JSONP' } });
});

MyApp.directive('masonry', function ($parse) {
    return {
        restrict: 'AC',
        link: function (scope, elem, attrs) {
            elem.masonry({ itemSelector: '.masonry-item', columnWidth: $parse(attrs.masonry)(scope) });
        }
    };        
});

MyApp.directive('masonryItem', function () {
    return {
        restrict: 'AC',
        link: function (scope, elem, attrs) {
            elem.imagesLoaded(function () {
               elem.parents('.masonry').masonry('reload');
            });
        }
    };        
});

MyApp.controller('MasonryCtrl', function ($scope, flickrPhotos) {
    $scope.photos = flickrPhotos.load({ tags: 'dogs' });
});

Шаблон:

<div class="masonry: 240;" ng-controller="MasonryCtrl">
    <div class="masonry-item" ng-repeat="item in photos.items">
        <img ng-src="{{ item.media.m }}" />
    </div>
</div>

4

Ця проблема виникає через політику моделі безпеки веб-додатків, що є політикою того самого оригіналу щодо оригіналу. Відповідно до цієї політики, веб-браузер дозволяє скриптам, що містяться на першій веб-сторінці, доступ до даних на другій веб-сторінці, але тільки якщо обидві веб-сторінки мають однакове походження. Це означає, що запитувач повинен відповідати точному хосту, протоколу та порту сайту, що запитує.

У нас є кілька варіантів, щоб закінчити цю проблему заголовка CORS.

  1. Використання проксі - у цьому рішенні ми запустимо проксі-сервер, що коли запит проходить через проксі-сервер, він виглядає так, що він має таке саме походження. Якщо ви використовуєте nodeJS, ви можете використовувати cors -будь-де, щоб зробити проксі-сервер. https://www.npmjs.com/package/cors-anywhere .

    Приклад : -

    var host = process.env.HOST || '0.0.0.0';
    var port = process.env.PORT || 8080;
    var cors_proxy = require('cors-anywhere');
    cors_proxy.createServer({
        originWhitelist: [], // Allow all origins
        requireHeader: ['origin', 'x-requested-with'],
        removeHeaders: ['cookie', 'cookie2']
    }).listen(port, host, function() {
        console.log('Running CORS Anywhere on ' + host + ':' + port);
    });
  2. JSONP - JSONP - це метод передачі даних JSON, не турбуючись про проблеми міждоменів. Він не використовує об'єкт XMLHttpRequest. Натомість він використовує <script>тег. https://www.w3schools.com/js/js_json_jsonp.asp

  3. Сторона сервера - на стороні сервера нам потрібно включити запити перехресного походження. Спочатку ми отримаємо попередньо просвічені запити (ВАРІАНТИ), і нам потрібно дозволити запит, який є кодом статусу 200 (добре).

    Попередньо заздалегідь запрошені спочатку надсилають заголовок запиту HTTP OPTIONS до ресурсу іншого домену, щоб визначити, чи безпечний для надсилання фактичний запит. Поточні запити попередньо відображаються таким чином, оскільки вони можуть мати значення для даних користувачів. Зокрема, запит попередньо перевіряється, якщо він використовує методи, відмінні від GET або POST. Крім того, якщо POST використовується для надсилання даних запиту із типом вмісту, відмінним від application / x-www-form-urlencoded, multipart / data-data, або text / plain, наприклад, якщо POST-запит надсилає на сервер корисну навантаження XML використовуючи application / xml або text / xml, тоді запит попередньо просвічується. Він встановлює власні заголовки у запиті (наприклад, у запиті використовується заголовок, наприклад X-PINGOTHER)

    Якщо ви користуєтеся пружиною, просто додавання наступного коду вирішить проблему. Тут я відключив маркер csrf, який не має значення увімкнення / відключення відповідно до вашої вимоги.

    @SpringBootApplication
    public class SupplierServicesApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(SupplierServicesApplication.class, args);
        }
    
        @Bean
        public WebMvcConfigurer corsConfigurer() {
            return new WebMvcConfigurerAdapter() {
                @Override
                public void addCorsMappings(CorsRegistry registry) {
                    registry.addMapping("/**").allowedOrigins("*");
                }
            };
        }
    }

    Якщо ви використовуєте джерело безпеки, використовуйте нижче код разом з вищевказаним кодом.

    @Configuration
    @EnableWebSecurity
    public class SupplierSecurityConfig extends WebSecurityConfigurerAdapter {
    
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.csrf().disable().authorizeRequests().antMatchers(HttpMethod.OPTIONS, "/**").permitAll().antMatchers("/**").authenticated().and()
                    .httpBasic();
        }
    
    }

2

Я зіткнувся з подібною проблемою, як ця, проблема була з бекендом. Я використовував сервер вузлів (Express). У мене був запит на отримання від переднього (кутового), як показано нижче

   onGetUser(){
        return this.http.get("http://localhost:3000/user").pipe(map(
            (response:Response)=>{
                const user =response.json();
                return user;
            }
        )) 
    }

Але це дало таку помилкуПомилка

Це резервний код, написаний за допомогою експресу без заголовків

app.get('/user',async(req,res)=>{
     const user=await getuser();
     res.send(user);
 })

Після додавання заголовка до методу проблема була вирішена

app.get('/user',async(req,res)=>{
    res.header("Access-Control-Allow-Origin", "*");
    const user=await getuser();
    res.send(user);
})

Ви можете отримати більш детальну інформацію про ввімкнення CORS на Node JS


1

Відповів сам.

Кут CORS js + restEasy на POST

Ну і нарешті я прийшов до цього вирішення: причина, з якою він працював з IE, полягає в тому, що IE надсилає безпосередньо POST замість того, щоб спочатку запит перед польотом запитати дозволу. Але я досі не знаю, чому фільтр не зміг керувати запитом OPTIONS і надсилає за замовчуванням заголовки, які не описані у фільтрі (здається, це переоцінка лише для цього випадку ... можливо, спокійна річ .. .)

Тому я створив шлях OPTIONS у своїй службі відпочинку, який переписує відповідь і включає заголовки у відповідь за допомогою заголовка відповіді.

Я все ще шукаю чистий спосіб це зробити, якщо хтось раніше стикався з цим.


1

Apache / HTTPD, як правило, існує на більшості підприємств або якщо ви використовуєте Centos / тощо вдома. Отже, якщо у вас це є, ви можете зробити проксі дуже легко додати необхідні заголовки CORS.

У мене є запис в блозі на цьому тут , як я страждав з ним досить багато раз в останній час . Але важливий біт - це просто додати це до вашого файлу /etc/httpd/conf/httpd.conf і переконатися, що ви вже виконуєте "Слухати 80":

<VirtualHost *:80>
    <LocationMatch "/SomePath">
       ProxyPass http://target-ip:8080/SomePath
       Header add "Access-Control-Allow-Origin" "*"
    </LocationMatch>
</VirtualHost>

Це гарантує, що всі запити до URL-адрес під маршрутом your-server-ip: 80 / SomePath до http: // target-ip: 8080 / SomePath (API без підтримки CORS) і повертаються з правильним Access-Control-Allow- Початковий заголовок, щоб вони могли працювати з вашим веб-додатком.

Звичайно, ви можете змінити порти і націлити на весь сервер, а не на SomePath, якщо вам подобається.


1

Ця відповідь окреслює два способи вирішення API, які не підтримують CORS:

  • Використовуйте проксі CORS
  • Використовуйте JSONP, якщо API підтримує його

Одним із варіантів вирішення проблеми є використання CORS PROXY:

angular.module("app",[])
.run(function($rootScope,$http) { 
     var proxy = "//cors-anywhere.herokuapp.com";
     var url = "http://api.ipify.org/?format=json";
     $http.get(proxy +'/'+ url)
       .then(function(response) {
         $rootScope.response = response.data;
     }).catch(function(response) {
         $rootScope.response = 'ERROR: ' + response.status;
     })     
})
<script src="//unpkg.com/angular/angular.js"></script>
<body ng-app="app">
   Response = {{response}}
</body>

Для отримання додаткової інформації див


Використовуйте JSONP, якщо API підтримує його:

 var url = "//api.ipify.org/";
 var trust = $sce.trustAsResourceUrl(url);
 $http.jsonp(trust,{params: {format:'jsonp'}})
   .then(function(response) {
     console.log(response);
     $scope.response = response.data;
 }).catch(function(response) {
     console.log(response);
     $scope.response = 'ERROR: ' + response.status;
 }) 

The DEMO на PLNKR

Для отримання додаткової інформації див


0
        var result=[];
        var app = angular.module('app', []);
        app.controller('myCtrl', function ($scope, $http) {
             var url="";// your request url    
             var request={};// your request parameters
             var headers = {
             // 'Authorization': 'Basic ' + btoa(username + ":" + password),
            'Access-Control-Allow-Origin': true,
            'Content-Type': 'application/json; charset=utf-8',
            "X-Requested-With": "XMLHttpRequest"
              }
             $http.post(url, request, {
                        headers
                 })
                 .then(function Success(response) {
                      result.push(response.data);             
                      $scope.Data = result;              
                 }, 
                  function Error(response) {
                      result.push(response.data);
                       $scope.Data = result;
                    console.log(response.statusText + " " + response.status)
               }); 
     });

And also add following code in your WebApiConfig file            
        var cors = new EnableCorsAttribute("*", "*", "*");
        config.EnableCors(cors);

"А також додайте наступний код у свій файл WebApiConfig" - Питання полягає у поданні запиту до Flickr. Їх сервери не перебувають під контролем ОП. Flickr, ймовірно, також не використовує ASP.NET.
Квентін

0

ми можемо ввімкнути CORS у передньому напрямку за допомогою модуля ngResourse. Але найголовніше, що ми повинні мати цей фрагмент коду, роблячи запит ajax в контролері,

$scope.weatherAPI = $resource(YOUR API,
     {callback: "JSON_CALLBACK"}, {get: {method: 'JSONP'}});
 $scope.weatherResult = $scope.weatherAPI.get(YOUR REQUEST DATA, if any);

Крім того, ви повинні додати ngResourse CDN у частині сценарію та додати як залежність у модулі програми.

<script src="https://code.angularjs.org/1.2.16/angular-resource.js"></script>

Потім використовуйте "ngResourse" у розділі залежності модуля додатка

var routerApp = angular.module("routerApp", ["ui.router", 'ngResource']);

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