使用Nginx / Chrome的跨源资源共享(CORS)


13

我有一个细分如下的网站:

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

我想同时允许example.comdevelopers.example.com向发出AJAX请求api.example.com

到目前为止,我的nginx配置 api.example.com,由麒麟提供)是一个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;
       }

}

根据我的阅读,这对于我想做的事情应该足够了。

选项的回应:

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失败(即使它返回200 OK)。

Answers:


17

根据CORS规范,多个来源应以空格隔开,而不是用逗号隔开,因此请尝试发送此标头:

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

Mozilla的文件没有提及多起源的,所以如果仍然无法正常工作只尝试发送:

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

如果可行,您将需要配置nginx或您的应用程序服务器以返回一个Access-Control-Allow-Origin标头,该Origin标头包含客户端发送的标头值(如果它与允许的列表匹配)。类似于以下(未试用的)nginx配置可以做到这一点:

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

这是我最终要做的一部分。我还删除了Access-Control-Allow-Header标头,并按如下方式修改了我的jQuery调用:$.ajax("http://api.example.com", { type: 'get', crossDomain: true}) 这完全阻止了OPTIONS预检。
约翰·莱德贝特

1
注意:如果给定的解决方案对您不起作用,请阅读。它很有启发性,您可能会发现它不起作用的原因。
its_me

4

在Nginx配置中像这样iflocation块中使用in :

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.