2014-04-09 17 views
73

Avevo sviluppato un'app PhoneGap che ora viene trasformata in un sito Web mobile. Tutto funziona senza problemi oltre a un piccolo problema. Uso una determinata API di terze parti tramite una richiesta POST, che funziona bene nell'app, ma non riesce nella versione del sito Web mobile.Come saltare la richiesta di preflight OPTIONS in AngularJS

Dopo uno sguardo ravvicinato, sembra che AngularJS (suppongo che il browser in realtà) stia inviando prima una richiesta OPTIONS. Oggi ho imparato molto su CORS, ma non riesco a capire come disabilitarlo del tutto. Non ho accesso a tale API (quindi i cambiamenti da quel lato sono impossibili), ma hanno aggiunto il dominio su cui sto lavorando alla loro intestazione Access-Control-Allow-Origin.

Questo è il codice che sto parlando:

 var request = { 
       language: 'fr', 
       barcodes: [ 
        { 
         barcode: 'somebarcode', 
         description: 'Description goes here' 
        } 
       ] 
      }; 
     } 
     var config = { 
      headers: { 
       'Cache-Control': 'no-cache', 
       'Content-Type': 'application/json' 
      } 
     }; 
     $http.post('http://somedomain.be/trackinginfo', request, config).success(function(data, status) { 
      callback(undefined, data); 
     }).error(function(data, status) { 
      var err = new Error('Error message'); 
      err.status = status; 
      callback(err); 
     }); 

Come posso impedire che il browser (o AngularJS) di inviare quella richiesta OPTIONS e saltare per la richiesta POST reale? Sto usando AngularJS 1.2.0.

Grazie in anticipo.

risposta

80

La verifica preliminare venga attivato dal Content-Type di application/json. Il modo più semplice per evitare ciò è impostare il tipo di contenuto in text/plain nel tuo caso. application/x-www-form-urlencoded & multipart/form-data Anche i tipi di contenuto sono accettabili, ma ovviamente è necessario formattare il carico utile della richiesta in modo appropriato.

Se si sta ancora visualizzando una verifica preliminare dopo aver apportato questa modifica, Angular potrebbe aggiungere anche un'intestazione X alla richiesta.

+9

Questa è la risposta corretta: le intestazioni Content-Type e Cache-Control stanno attivando una richiesta di verifica preliminare. Un semplice GET con un Content-Type di text/plain e pochi altri sono gli unici modi per attivare una richiesta non preflight. Vedi: https: //developer.mozilla.org/en-US/docs/HTTP/Access_control_CORS#Preflighted_requests –

+0

Ah sì, ho dimenticato di Cache-Control. –

+7

Un'intestazione personalizzata attiverà anche il preflight. –

11

Come quello che ha detto Ray, si può fermare modificando il contenuto-header come -

$http.defaults.headers.post["Content-Type"] = "text/plain"; 

per esempio -

angular.module('myApp').factory('User', ['$resource','$http', 
    function($resource,$http){ 
     $http.defaults.headers.post["Content-Type"] = "text/plain"; 
     return $resource(API_ENGINE_URL+'user/:userId', {}, { 
      query: {method:'GET', params:{userId:'users'}, isArray:true}, 
      getLoggedIn:{method:'GET'} 
     }); 
    }]); 

o direttamente ad una chiamata -

var req = { 
method: 'POST', 
url: 'http://example.com', 
headers: { 
    'Content-Type': 'text/plain' 
}, 
data: { test: 'test' } 
} 

$http(req).then(function(){...}, function(){...}); 

Questo non invierà alcuna richiesta opzione di pre-volo.

NOTA: richiesta non dovrebbe avere alcun parametro di intestazione personalizzata, se richiesta intestazione contiene alcuna intestazione personalizzata del browser quindi farà richiesta pre-volo, non puoi evitarlo.

+1

Come dovrei farlo solo con '$ http'? – learnercys

+0

@learnercys controlla l'ultimo codice (direttamente in una chiamata)? – Vivek

+0

Grazie, è simile a quello che stavo facendo. Le uniche modifiche sono il metodo 'GET' e un'ulteriore intestazione' Autorizzazione'. Ma ancora inviando il preflight. – learnercys

1

Quando si eseguono determinati tipi di richieste AJAX tra domini, i browser moderni che supportano CORS inseriranno una richiesta extra "preflight" per determinare se sono autorizzati ad eseguire l'azione. Da esempio di query:

$http.get(‘https://example.com/api/v1/users/’ +userId, 
    {params:{ 
      apiKey:’34d1e55e4b02e56a67b0b66’ 
      } 
    } 
); 

Come risultato di questo frammento si può vedere che l'indirizzo è stato inviato due richieste (opzioni e GET). La risposta dal server include le intestazioni che confermano la permissibilità alla query GET. Se il tuo server non è configurato per elaborare correttamente una richiesta OPTIONS, le richieste del client falliranno. Ad esempio:

Access-Control-Allow-Credentials: true 
Access-Control-Allow-Headers: accept, origin, x-requested-with, content-type 
Access-Control-Allow-Methods: DELETE 
Access-Control-Allow-Methods: OPTIONS 
Access-Control-Allow-Methods: PUT 
Access-Control-Allow-Methods: GET 
Access-Control-Allow-Methods: POST 
Access-Control-Allow-Orgin: * 
Access-Control-Max-Age: 172800 
Allow: PUT 
Allow: OPTIONS 
Allow: POST 
Allow: DELETE 
Allow: GET 
-1

impostare il tipo di contenuto di indefinito renderebbe JavaScript passare i dati di intestazione Come è, e sopra la scrittura del angolari $ httpProvider configurazioni intestazione predefinita.Angular $http Documentation

$http({url:url,method:"POST", headers:{'Content-Type':undefined}).then(success,failure); 
2

Penso modo migliore è controllare se la richiesta è di tipo "OPZIONI" tornano a 200 da middle ware. Ha funzionato per me.

express.use('*',(req,res,next) =>{ 
     if (req.method == "OPTIONS") { 
     res.status(200); 
     res.send(); 
     }else{ 
     next(); 
     } 
    }); 
-1

È necessario modificare due file. 1 - In primo luogo nel file web.config del client aggiungere il tag sotto system.webServer tag

<httpProtocol> 
     <customHeaders> 
      <add name="Access-Control-Allow-Origin" value="*"/> 
      <add name="Access-Control-Allow-Headers" value="Content-Type" /> 
      <add name="Access-Control-Allow-Methods" value="GET, POST, PUT, 
      DELETE, OPTIONS" /> 
     </customHeaders> 
</httpProtocol> 

2 - Nel file Global.asax del server di

protected void Application_BeginRequest() { if (Request.Headers.AllKeys.Contains ("Origin") & & Request.HttpMethod == "OPTIONS") { Response.Flush(); } }

Problemi correlati