Cross Origin Resource Sharing (CORS) con nginx / chrome


13

Ho un sito Web con la seguente segmentazione:

api.example.com 
developers.example.com 
example.com

Vorrei consentire entrambi example.come developers.example.comfare richieste AJAX a api.example.com.

La mia configurazione nginx finora api.example.com, che è un'app Rack servita da unicorno, è simile a questa:

upstream app_server {
  server unix:/tmp/api.example.com.sock fail_timeout=0;
}

server {
       listen 80;
       server_name api.example.com;
       access_log /home/nginx/api.example.com/log/access.log;
       error_log /home/nginx/api.example.com/log/error.log;
       location / {
         add_header 'Access-Control-Allow-Origin' 'http://example.com,http://developers.example.com';
         add_header 'Access-Control-Allow-Credentials' 'true';
         add_header 'Access-Control-Allow-Headers' 'Content-Type,Accept';
         add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, PUT, DELETE';

         proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
         proxy_set_header Host $http_host;
         proxy_redirect off;
         proxy_pass http://app_server;
       }

}

Sulla base della mia lettura, questo dovrebbe essere sufficiente per quello che sto cercando di fare.

La risposta OPTIONS :

HTTP/1.1 200 OK
Server: nginx/0.7.67
Date: Sat, 28 Apr 2012 17:20:08 GMT
Content-Type: application/json
Connection: close
Status: 200 OK
Content-Length: 0
Access-Control-Allow-Origin: http://developers.example.com,http://example.com
Access-Control-Allow-Credentials: true
Access-Control-Allow-Headers: Content-Type,Accept
Access-Control-Allow-Methods: GET, POST, OPTIONS, PUT, DELETE

Ma quando provo quanto segue nella console di Chrome:

$.ajax("http://api.example.com", {
  type: 'get',
  contentType: "application/json",
  accept: "application/json"
}).success(function(data){
  console.log("success!", data);
}).fail(function(jqxhr, statusText){
  console.log("fail!", jqxhr, statusText);
})

Vedo:

XMLHttpRequest cannot load http://api.example.com/. Origin
http://developers.example.com is not allowed by Access-Control-Allow-Origin.

E lo stesso per http://example.com .

Cosa mi sto perdendo?

Se ho impostato il Access-Control-Allow-Originper *poi vedo:

HTTP/1.1 200 OK
Server: nginx/0.7.67
Date: Sat, 28 Apr 2012 17:28:41 GMT
Content-Type: application/json
Connection: close
Status: 200 OK
Content-Length: 0
Access-Control-Allow-Origin: *
Access-Control-Allow-Headers: Content-Type,Accept
Access-Control-Allow-Methods: GET, POST, OPTIONS, PUT, DELETE

Ma la richiesta jQuery non riesce ancora, con Chrome che evidenzia anche il OPTIONSfallimento del pre-volo (anche se è tornato 200 OK).

Risposte:


17

Secondo le specifiche CORS più origini dovrebbero essere separate da spazi, non virgole come hai usato, quindi prova a inviare questa intestazione:

Access-Control-Allow-Origin: http://developers.example.com http://example.com

La documentazione di Mozilla non menziona però più origini, quindi se continua a non funzionare, prova solo a inviare:

Access-Control-Allow-Origin: http://developers.example.com

Se funziona, dovrai configurare nginx o il tuo server delle applicazioni per restituire Access-Control-Allow-Originun'intestazione contenente il valore Origindell'intestazione inviata dal client se corrisponde all'elenco consentito. Qualcosa come la seguente configurazione nginx (non testata) potrebbe farlo:

if ($http_origin ~ "^(http://developers.example.com|http://example.com)$") {
    add_header "Access-Control-Allow-Origin" $http_origin;
}

Questo fa parte di quello che ho finito per fare. Ho anche rimosso l' Access-Control-Allow-Headerintestazione e modificato la mia chiamata jQuery in questo modo: $.ajax("http://api.example.com", { type: 'get', crossDomain: true}) ciò ha impedito che si verificasse il OPTIONSpreflight.
John Ledbetter,

1
NOTA: se la soluzione fornita non funziona per te, leggi questo e questo . È illuminante e potresti scoprire il motivo per cui non funziona.
its_me,

4

Usando un ifin un locationblocco in una configurazione nginx come questa:

if ($http_origin ~ "^(http://developers.example.com|http://example.com)$") {
    add_header "Access-Control-Allow-Origin" $http_origin;
}

Fai in modo che nginx faccia cose strane. In particolare, proxy_passe try_filesnon funziona come previsto. Vedi http://wiki.nginx.org/IfIsEvil per maggiori informazioni.

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.