Cross Origin Resource Sharing (CORS) dengan nginx / chrome

13

Saya memiliki situs web dengan segmentasi berikut:

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

Saya ingin mengizinkan keduanya example.comdan developers.example.commembuat permintaan AJAX api.example.com.

Konfigurasi nginx saya sejauh ini api.example.com, yang merupakan aplikasi Rack yang dilayani oleh unicorn, terlihat seperti ini:

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

}

Berdasarkan bacaan saya, ini seharusnya cukup untuk apa yang saya coba lakukan.

The PILIHAN respon:

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

Tetapi ketika saya mencoba yang berikut di konsol 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);
})

Saya melihat:

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

Dan hal yang sama untuk http://example.com .

Apa yang saya lewatkan?

Jika saya mengatur Access-Control-Allow-Originuntuk *maka saya melihat:

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

Tetapi permintaan jQuery masih gagal, dengan chrome juga menyoroti bahwa pra-penerbangan OPTIONSgagal (meskipun dikembalikan 200 OK).

John Ledbetter
sumber

Jawaban:

17

Menurut spesifikasi CORS, beberapa asal harus dipisahkan oleh spasi, bukan koma seperti yang Anda gunakan, jadi coba kirim tajuk ini:

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

The dokumentasi Mozilla tidak menyebutkan asal-usul beberapa meskipun, jadi jika itu masih tidak mencoba bekerja hanya mengirimkan:

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

Jika berhasil, Anda harus mengonfigurasi nginx atau server aplikasi Anda untuk mengembalikan Access-Control-Allow-Originheader yang berisi nilai Originheader yang dikirim oleh klien jika cocok dengan daftar yang diizinkan. Sesuatu seperti konfigurasi nginx berikut (yang belum diuji) dapat melakukan itu:

if ($http_origin ~ "^(http://developers.example.com|http://example.com)$") {
    add_header "Access-Control-Allow-Origin" $http_origin;
}
Mgorven
sumber
Ini adalah bagian dari apa yang akhirnya saya lakukan. Saya juga menghapus Access-Control-Allow-Headerheader, dan memodifikasi panggilan jQuery saya seperti ini: $.ajax("http://api.example.com", { type: 'get', crossDomain: true}) Yang mencegah OPTIONSpreflight terjadi sama sekali.
John Ledbetter
1
CATATAN: Jika solusi yang diberikan tidak bekerja untuk Anda, baca ini dan ini . Ini mencerahkan, dan Anda mungkin menemukan alasan itu tidak bekerja.
its_me
4

Menggunakan ifin dalam locationblok dalam konfigurasi nginx seperti ini:

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

Menyebabkan nginx untuk melakukan hal-hal aneh. Secara khusus, proxy_passdan try_filestidak berfungsi seperti yang diharapkan. Lihat http://wiki.nginx.org/IfIsEvil untuk info lebih lanjut.

Anthony Moralez
sumber