使用nginx / chrome跨源数据共享(CORS)

我有一个网站,具有以下细分:

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

我希望允许example.comdevelopers.example.comapi.example.com发出AJAX请求。

我的nginxconfiguration至今为api.example.com ,这是一个由独angular兽服务的Rack应用程序,看起来像这样:

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

根据我的阅读,这应该足够我想要做的。

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 

但是,当我在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); }) 

我懂了:

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

和http://example.com一样 。

我错过了什么?

如果我将Access-Control-Allow-Origin*那么我看到:

 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 

但是jQuery请求仍然失败,chrome还突出显示了飞行前OPTIONS失败(尽pipe返回200 OK )。

根据CORS规范,多个起源应该用空格分隔,而不是像以前那样用逗号分开,所以请尝试发送这个标题:

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

Mozilla的文档虽然没有提到多个来源,所以如果仍然无法正常工作,只能发送:

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

如果这样的话,你需要configurationnginx或者你的应用服务器来返回一个Access-Control-Allow-Origin头,该头包含客户端发送的Origin头的值(如果它匹配的是允许的列表)。 像下面的(未经testing的)nginxconfiguration可以做到这一点:

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

在像这样的nginxconfiguration中的一个location块中使用if

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

导致nginx做奇怪的事情。 具体来说, proxy_passtry_files不按预期工作。 有关更多信息,请参阅http://wiki.nginx.org/IfIsEvil