Как включить 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

ankitr
источник
1
Вы должны запросить данные у вашего прокси, вы все равно запрашиваете их непосредственно у flickr.
Квентин
@quentin Спасибо за быстрый ответ. Можете ли вы дать мне демо.
ankitr
1
Вы просто измените URL с flickr.com на URL вашего прокси
Квентин
1
Но как я буду называть Flickr? как мне нужны изображения из Flickr.
Ankitr
2
Клиент вызывает прокси. Прокси вызывает flickr. Вот что значит прокси. (Ваш прокси-код ... не является прокси, это веб-сервер для обслуживания JSON и JSONP из статических файлов).
Квентин

Ответы:

194

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

Quentin
источник
1
Вместо этого отправляйте запросы на Flickr с вашего сервера.
Квентин
Я не использую сервер, но я могу использовать node.js. Можете ли вы показать мне путь с этим?
ankitr
1
Не в месте, доступном в комментарии. Это довольно большой набор тем.
Квентин
Почему это , что я могу получить ответ от https://www.google.comиспользования приложения , как POSTMAN, но когда я пытаюсь GETс https://www.google.comпомощью вызова AJAX я получаю ошибку CORS? Разве я не могу заставить вызов AJAX вести себя так же, как вызов POSTMAN?
AjaxLeung
6
@AlexLeung - Почтальон - установленное приложение. Если ваш веб-сайт может запросить у моего браузера данные из Google и прочитать их, то ваш веб-сайт может запросить мою страницу почтового ящика GMail и прочитать всю мою электронную почту. Это было бы ужасно.
Квентин
64

У меня была аналогичная проблема , и для меня это сводилось к добавлению следующих HTTP заголовки в ответ на приемном конце :

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

Вы можете предпочесть не использовать *в конце, а только имя домена хоста, отправляющего данные. подобно*.example.com

Но это возможно только тогда, когда у вас есть доступ к конфигурации сервера.

Erwin
источник
2
Я новичок в AngularJs. Подскажите пожалуйста, где это реализовать?
Ankitr
18
@Ankit Вам нужно добавить эти заголовки на сервере , а не в AngularJS.
Фелипе
2
@techcraver - вам не нужен оперативный доступ к конфигурации сервера - просто передайте заголовки из вашего скрипта. Если у вас есть бэкэнд PHP, это будетheader('Access-Control-Allow-Origin: *');
Давидконрад
@davidkonrad: я создал целое приложение в angular v4. Можете ли вы сказать, где я должен включить эти заголовки: /
Pygirl
@Pygirl, я полагаю, вы сделали клиентский угол в углу? Вам необходимо добавить заголовки на стороне сервера ответов, как и где зависит от технологии. Если это PHP-сценарий, который вы вызываете с углового Http.get()или аналогичного значения, добавьте header('Access-Control-Allow-Origin: *')в качестве самого первого вывода в вызываемый PHP-сценарий (т.
Е.
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 вы можете использовать Корс в любом месте , чтобы сделать прокси вещи. 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 используется для отправки данных запроса с Content-Type, отличным от application / x-www-form-urlencoded, multipart / form-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("*");
                }
            };
        }
    }

    Если вы используете систему безопасности Spring, используйте приведенный ниже код вместе с приведенным выше кодом.

    @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). У меня был запрос get от внешнего интерфейса (угловой), как показано ниже

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

Но это дало следующую ошибкуОшибка

Это внутренний код, написанный с использованием Express без заголовков.

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 и отправляет заголовки по умолчанию, которые не описаны в фильтре (похоже, переопределение для этого единственного случая ... может быть, restEasy ... .)

Поэтому я создал путь OPTIONS в моей службе отдыха, который переписывает ответ и включает заголовки в ответ, используя заголовок ответа.

Я все еще ищу чистый способ сделать это, если кто-нибудь сталкивался с этим раньше.

j.doe
источник
1

Apache / HTTPD обычно присутствует на большинстве предприятий или если вы используете Centos / etc дома. Так что, если у вас это есть, вы можете очень легко создать прокси, чтобы добавить необходимые заголовки CORS.

У меня есть пост в блоге по этому вопросу здесь, поскольку я страдал с ним довольно много раз в последнее время. Но важный момент - это просто добавить это в файл /etc/httpd/conf/httpd.conf и убедиться, что вы уже выполняете «Listen 80»:

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

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

Конечно, вы можете изменить порты и настроить таргетинг на весь сервер, а не на SomePath, если хотите.

Джон Хамфрис - w00te
источник
1

Этот ответ описывает два способа обхода API, которые не поддерживают CORS:

  • Используйте CORS Proxy
  • Используйте 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;
 }) 

DEMO на PLNKR

Для получения дополнительной информации см.

georgeawg
источник
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']);

Алок Ранджан
источник