Cross Origin Resource Sharing (CORS) mit nginx / chrome

13

Ich habe eine Website mit folgender Segmentierung:

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

Ich möchte beides zulassen example.comund developers.example.comAJAX-Anfragen stellen api.example.com.

Meine bisherige Nginx-Konfiguration api.example.com, bei der es sich um eine Rack-App handelt, die von Unicorn bereitgestellt wird, sieht folgendermaßen aus:

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

}

Basierend auf meiner Lektüre sollte dies für das, was ich versuche, ausreichen.

Die Antwort von 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

Aber wenn ich das Folgende in der Chrome-Konsole versuche:

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

Aha:

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

Und das Gleiche für http://example.com .

Was vermisse ich?

Wenn ich auf setze Access-Control-Allow-Origin, *sehe ich:

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

Die jQuery-Anforderung schlägt jedoch immer noch fehl, wobei Chrome außerdem darauf hinweist, dass der Vorflug OPTIONSfehlgeschlagen ist (obwohl er zurückgegeben wurde 200 OK).

John Ledbetter
quelle

Antworten:

17

Gemäß der CORS-Spezifikation sollten mehrere Ursprünge durch Leerzeichen und nicht durch Kommas getrennt werden. Versuchen Sie also, den folgenden Header zu senden:

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

In der Mozilla-Dokumentation werden jedoch nicht mehrere Ursprünge erwähnt. Wenn dies immer noch nicht funktioniert, senden Sie einfach Folgendes:

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

Wenn dies funktioniert, müssen Sie nginx oder Ihren Anwendungsserver so konfigurieren, dass er einen Access-Control-Allow-OriginHeader zurückgibt, der den Wert des Originvom Client gesendeten Headers enthält, wenn dieser mit der zulässigen Liste übereinstimmt. So etwas wie die folgende (nicht getestete) Nginx-Konfiguration könnte das tun:

if ($http_origin ~ "^(http://developers.example.com|http://example.com)$") {
    add_header "Access-Control-Allow-Origin" $http_origin;
}
mgorven
quelle
Dies ist ein Teil dessen, was ich getan habe. Ich habe auch den Access-Control-Allow-HeaderHeader entfernt und meinen jQuery-Aufruf wie folgt geändert: $.ajax("http://api.example.com", { type: 'get', crossDomain: true}) Dadurch konnte der OPTIONSPreflight überhaupt nicht durchgeführt werden.
John Ledbetter
1
HINWEIS: Wenn die angegebene Lösung für Sie nicht funktioniert, lesen Sie dies und das . Es ist aufschlussreich, und Sie können den Grund finden, warum es nicht funktioniert.
its_me
4

Verwenden von ifin einem locationBlock in einer Nginx-Konfiguration wie folgt:

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

Veranlassen Sie Nginx, seltsame Dinge zu tun. Insbesondere proxy_passund try_filesfunktionieren nicht wie erwartet. Weitere Informationen finden Sie unter http://wiki.nginx.org/IfIsEvil .

Anthony Moralez
quelle