Udostępnianie zasobów między źródłami (CORS) z nginx / chrome

13

Mam stronę internetową z następującą segmentacją:

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

Chciałbym zezwolić na oba te elementy example.comi developers.example.comwysyłać żądania AJAX do api.example.com.

Moja dotychczasowa konfiguracja nginx api.example.com, czyli aplikacja Rack obsługiwana przez jednorożca, wygląda następująco:

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

}

Na podstawie mojego czytania powinno to wystarczyć do tego, co próbuję zrobić.

Odpowiedź OPCJE :

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

Ale kiedy próbuję wykonać następujące czynności w konsoli 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);
})

Widzę:

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

To samo dotyczy http://example.com .

czego mi brakuje?

Jeżeli ustawić Access-Control-Allow-Originaby *potem widzę:

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

Ale żądanie jQuery nadal się nie udaje, a chrome podkreśla również, że lot przed lotem OPTIONSnie powiódł się (mimo że powrócił 200 OK).

John Ledbetter
źródło

Odpowiedzi:

17

Zgodnie ze specyfikacją CORS wiele początków powinno być oddzielonych spacjami, a nie przecinkami, tak jak użyłeś, więc spróbuj wysłać ten nagłówek:

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

Dokumentacja Mozilli nie wspomina jednak o wielu źródłach, więc jeśli to nadal nie działa, spróbuj wysłać tylko:

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

Jeśli to zadziała, musisz skonfigurować nginx lub serwer aplikacji, aby zwracał Access-Control-Allow-Originnagłówek zawierający wartość Originnagłówka wysłanego przez klienta, jeśli jest on zgodny z dozwoloną listą. Może to zrobić coś takiego (następująca (nie przetestowana) konfiguracja nginx):

if ($http_origin ~ "^(http://developers.example.com|http://example.com)$") {
    add_header "Access-Control-Allow-Origin" $http_origin;
}
mgorven
źródło
To część tego, co skończyłem. Ja również usunąć ten Access-Control-Allow-Headernagłówek, i modyfikowane moje wezwanie jQuery tak: $.ajax("http://api.example.com", { type: 'get', crossDomain: true}) Który uniemożliwił OPTIONSInspekcja wstępna dzieje w ogóle.
John Ledbetter
1
UWAGA: Jeśli dane rozwiązanie nie działa dla Ciebie, przeczytaj to i to . Jest pouczający i możesz znaleźć powód, dla którego nie działa.
its_me
4

Używanie ifw locationbloku w konfiguracji nginx w następujący sposób:

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

Powoduj, że nginx robi dziwne rzeczy. W szczególności proxy_passi try_filesnie działają zgodnie z oczekiwaniami. Więcej informacji można znaleźć na stronie http://wiki.nginx.org/IfIsEvil .

Anthony Moralez
źródło