Come abilitare CORS in AngularJs


147

Ho creato una demo usando JavaScript per l'API di ricerca di foto di Flickr. Ora lo sto convertendo in AngularJs. Ho cercato su internet e ho trovato di seguito la configurazione.

Configurazione:

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

Servizio:

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

controller:

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

Ma ho ancora lo stesso errore. Ecco alcuni link che ho provato:

XMLHttpRequest non può caricare l'URL. Origine non consentita da Access-Control-Allow-Origin

http://goo.gl/JuS5B1


1
Devi richiedere i dati dal tuo proxy, lo stai ancora richiedendo direttamente da Flickr.
Quentin,

@quentin Grazie per la rapida risposta. Potete per favore darmi una demo.
ankitr,

1
Devi solo cambiare l'URL da flickr.com nell'URL del tuo proxy
Quentin

1
Ma come chiamerò flickr? come ho bisogno delle immagini da flickr.
ankitr,

2
Il client chiama il proxy. Il proxy chiama flickr. Questo è ciò che significa proxy. (Il tuo codice proxy ... non è un proxy, è un server web per servire JSON e JSONP da file statici).
Quentin,

Risposte:


194

Non Il server a cui stai effettuando la richiesta deve implementare CORS per concedere JavaScript dall'accesso al tuo sito web. Il tuo JavaScript non può autorizzarsi ad accedere a un altro sito web.


1
Invia invece le richieste a Flickr dal tuo server.
Quentin,

Non sto usando un server ma posso usare node.js. Puoi mostrarmi la strada con questo?
Ankitr

1
Non nello spazio disponibile in un commento. È piuttosto un grande insieme di argomenti.
Quentin,

Perché è che posso ottenere una risposta da https://www.google.comutilizzare un'applicazione come postino, ma quando provo a GETda https://www.google.comutilizzando una chiamata AJAX ottengo l'errore CORS? Non è possibile che la chiamata AJAX si comporti in modo simile alla chiamata di POSTMAN?
AjaxLeung,

6
@AlexLeung - Postman è un'applicazione installata. Se il tuo sito web potrebbe fare in modo che il mio browser richieda i dati a Google e li legga, il tuo sito Web potrebbe richiedere la mia pagina Posta in arrivo GMail e leggere tutta la mia e-mail. Sarebbe terribile.
Quentin,

64

Ho avuto un problema simile e per me è riassunta in aggiungendo la seguente intestazioni HTTP alla risposta del lato ricevente :

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

Potresti preferire non utilizzare il *alla fine, ma solo il nome di dominio dell'host che invia i dati. Piace*.example.com

Ma questo è fattibile solo quando si ha accesso alla configurazione del server.


2
Sono nuovo in AngularJs. Per favore, puoi dirmi dove implementarlo?
ankitr,

18
@Ankit Devi aggiungere queste intestazioni nel server , non in AngularJS.
Felipe,

2
@techcraver - Non è necessario l'accesso operativo alla configurazione del server - basta passare le intestazioni all'interno dello script. Se hai un back-end PHP, sarebbeheader('Access-Control-Allow-Origin: *');
davidkonrad,

@davidkonrad: ho creato l'intera app in angular v4. Puoi dirmi dove devo includere queste intestazioni: /
Pygirl

@Pygirl, credo che tu abbia reso angolare il lato cliente? È necessario aggiungere intestazioni al server di risposta, come e dove dipendono dalla tecnologia. Se si tratta di uno script PHP che chiami da un angolare Http.get()o simile, aggiungi header('Access-Control-Allow-Origin: *')come primo output nello script PHP chiamato (ovvero prima di generare l'effettiva risposta, JSON, che mai.
davidkonrad

9

Prova a utilizzare il servizio risorse per utilizzare jsonp flickr:

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

Modello:

<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

Questo problema si verifica a causa della politica del modello di sicurezza dell'applicazione Web che è la stessa politica di origine In base alla politica, un browser Web consente agli script contenuti in una prima pagina Web di accedere ai dati in una seconda pagina Web, ma solo se entrambe le pagine Web hanno la stessa origine. Ciò significa che il richiedente deve corrispondere all'host, al protocollo e alla porta esatti del sito richiedente.

Abbiamo più opzioni per superare questo problema di intestazione CORS.

  1. Utilizzo del proxy - In questa soluzione eseguiremo un proxy in modo tale che quando la richiesta passa attraverso il proxy sembrerà che abbia la stessa origine. Se stai usando il nodeJS puoi usare cors ovunque per fare le cose del proxy. https://www.npmjs.com/package/cors-anywhere .

    Esempio : -

    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 è un metodo per inviare dati JSON senza preoccuparsi di problemi tra domini. Non utilizza l'oggetto XMLHttpRequest, ma utilizza il <script>tag. https://www.w3schools.com/js/js_json_jsonp.asp

  3. Lato server: lato server è necessario abilitare le richieste di origine incrociata. Per prima cosa otterremo le richieste preflight (OPZIONI) e dobbiamo consentire la richiesta che è il codice di stato 200 (ok).

    Le richieste di verifica preliminare inviano innanzitutto un'intestazione di richiesta OPTIONS HTTP alla risorsa sull'altro dominio, al fine di determinare se la richiesta effettiva è sicura da inviare. Le richieste tra siti sono preflight in questo modo poiché potrebbero avere implicazioni per i dati dell'utente. In particolare, una richiesta viene preflight se utilizza metodi diversi da GET o POST. Inoltre, se POST viene utilizzato per inviare dati di richiesta con un tipo di contenuto diverso da application / x-www-form-urlencoded, multipart / form-data o text / plain, ad esempio se la richiesta POST invia un payload XML al server usando application / xml o text / xml, la richiesta viene preflight. Imposta le intestazioni personalizzate nella richiesta (ad es. La richiesta utilizza un'intestazione come X-PINGOTHER)

    Se stai usando la molla, basta aggiungere il codice qui sotto per risolvere il problema. Qui ho disabilitato il token csrf che non importa abilita / disabilita in base alle tue esigenze.

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

    Se si utilizza la sicurezza di primavera, utilizzare il codice seguente insieme al codice sopra.

    @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

Ho riscontrato un problema simile come questo, il problema era con il backend. Stavo usando il server dei nodi (Express). Ho ricevuto una richiesta dal frontend (angolare) come mostrato di seguito

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

Ma ha dato il seguente erroreL'errore

Questo è il codice di backend scritto usando express senza le intestazioni

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

Dopo aver aggiunto un'intestazione al problema del metodo è stato risolto

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

È possibile ottenere ulteriori dettagli sull'abilitazione di CORS sul nodo JS


1

Ho risposto da solo.

CORS j angolare + restEasy su POST

Bene, finalmente sono arrivato a questa soluzione alternativa: il motivo per cui ha funzionato con IE è perché IE invia direttamente un POST anziché prima una richiesta di verifica preliminare per chiedere l'autorizzazione. Ma ancora non so perché il filtro non è stato in grado di gestire una richiesta OPTIONS e invia per impostazione predefinita le intestazioni che non sono descritte nel filtro (sembra una sostituzione per quel solo caso ... forse una cosa restEasy .. .)

Quindi ho creato un percorso OPTIONS nel mio servizio di riposo che riscrive la risposta e include le intestazioni nella risposta utilizzando l'intestazione della risposta

Sto ancora cercando il modo pulito per farlo se qualcuno lo ha affrontato prima.


1

Apache / HTTPD tende ad essere presente nella maggior parte delle aziende o se stai usando Centos / etc a casa. Quindi, se ce l'hai in giro, puoi fare un proxy molto facilmente per aggiungere le intestazioni CORS necessarie.

Ho un post sul blog qui perché ne ho sofferto parecchie volte di recente. Ma la cosa importante è semplicemente aggiungere questo al tuo file /etc/httpd/conf/httpd.conf e assicurarti di fare già "Listen 80":

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

Questo assicura che tutte le richieste agli URL sotto il tuo-server-ip: 80 / SomePath instradino a http: // target-ip: 8080 / SomePath (l'API senza supporto CORS) e che restituiscano con il corretto controllo di accesso-Consenti- Intestazione Origin per consentire loro di lavorare con la tua app Web.

Ovviamente puoi cambiare le porte e scegliere come target l'intero server anziché SomePath, se lo desideri.


1

Questa risposta delinea due modi per aggirare le API che non supportano CORS:

  • Utilizzare un proxy CORS
  • Utilizzare JSONP se l'API lo supporta

Una soluzione alternativa è utilizzare un 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>

Per ulteriori informazioni, vedere


Utilizzare JSONP se l'API lo supporta:

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

La DEMO su PLNKR

Per ulteriori informazioni, vedere


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

"E aggiungi anche il seguente codice nel tuo file WebApiConfig" - La domanda è su come effettuare una richiesta a Flickr. I loro server non sono sotto il controllo dell'OP. Probabilmente Flickr non sta usando ASP.NET.
Quentin,

0

possiamo abilitare CORS nel frontend usando il modulo ngResourse. Ma soprattutto, dovremmo avere questo pezzo di codice mentre facciamo la richiesta ajax nel controller,

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

Inoltre, è necessario aggiungere ngResourse CDN nella parte dello script e aggiungere come dipendenza nel modulo dell'app.

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

Quindi utilizzare "ngResourse" nella sezione delle dipendenze del modulo app

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

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.