我有一个网站,其细分如下:
api.example.com
developers.example.com
example.com
我想允许两者example.com
并向developers.example.com
发出 AJAX 请求api.example.com
。
到目前为止api.example.com
,我的 nginx 配置(由 unicorn 提供服务的 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
)。
答案1
根据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;
}
答案2
if
在 nginx 配置中的一个块中使用location
如下:
if ($http_origin ~ "^(http://developers.example.com|http://example.com)$") {
add_header "Access-Control-Allow-Origin" $http_origin;
}
导致 nginx 出现奇怪的情况。具体来说,proxy_pass
就是try_files
无法按预期工作。请参阅http://wiki.nginx.org/IfIsEvil了解更多信息。