javascript 当后续请求的答案是 204 时,为什么 OPTIONS 请求会失败?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/13321168/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Why does an OPTIONS request fail when the answer to the follow up request is a 204?
提问by GeorgieF
I'm building a Backbone.js based app and face a strange issue.
我正在构建一个基于 Backbone.js 的应用程序并面临一个奇怪的问题。
At a certain point the app requests a collection resource and inside Chrome (and Safari) I get an error like that:
在某个时候,应用程序请求一个集合资源,在 Chrome(和 Safari)中,我收到如下错误:
XMLHttpRequest cannot load http://api.mydomain.net/v1/foos/00000d/bars/000014/boots Origin http://localhost:3501 is not allowed by Access-Control-Allow-Origin.
Ok, CORS issue I thought and blamed my API. Then requested this very resource via CURL:
好的,我想并归咎于我的 API 的 CORS 问题。然后通过 CURL 请求这个资源:
curl -i -H'Accept: application/json' -H'X-Auth-Token: pAWp5hrCmXA83GgFzgHC' -XOPTIONS 'http://api.mydomain.net/v1/foos/00000d/bars/000014/boots'
HTTP/1.1 200 OK
Status: 200
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Allow-Headers: DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,X-Auth-Token
Content-Length: 0
looks good, now the GET:
看起来不错,现在 GET:
curl -i -H'Accept: application/json' -H'X-Auth-Token: pAWp5hrCmXA83GgFzgHC' -XGET 'http://api.mydomain.net/v1/foos/00000d/bars/000014/boots'
HTTP/1.1 204 No Content
Status: 204
Cache-Control: no-cache
Content-Length: 0
Content-Type: text/plain
In case I request boots collection that contain at least one object, everything works fine. The CORS headers my server responds with arr totally fine as I think. So why do the browsers report a cross origin resource problem?
如果我请求包含至少一个对象的靴子集合,一切正常。我的服务器响应 arr 的 CORS 标头完全没问题。那么为什么浏览器会报告跨源资源问题呢?
Is it due to the content type text/plain
of my 204 responses?
是不是因为text/plain
我的 204 响应的内容类型?
Preflight (OPTIONS) request in dev tools:
回答by Rob W
You have to also include the Access-Control-Allow-Origin
in the response headers of the second request. That's not a client-side issue, but a backend one.
您还必须Access-Control-Allow-Origin
在第二个请求的响应标头中包含 。这不是客户端问题,而是后端问题。
This behaviour is in accordance with the CORS specification, applied in the following explanation (section 7.1.5 "Cross-Origin Request with Preflight"):
此行为符合CORS 规范,适用于以下说明(第 7.1.5 节“带有预检的跨域请求”):
- Preflight request (detailsomitted)
- "Set the cross-origin request statusto preflight complete."
- "This is the actual request. (...) observe the request rules below while making the request."
If the response has an HTTP status code of 301, 302, 303, or 307Not applicableIf the end user cancels the requestNot applicableIf there is a network errorNot applicable- Otherwise
Perform a resource sharing check. If it returns fail, apply the cache and network error steps.
- 预检请求(细节省略)
- “将跨域请求状态设置为预检完成。”
- “这是实际的请求。(...)在提出请求时遵守下面的请求规则。”
如果响应的 HTTP 状态代码为 301、302、303 或 307不适用如果最终用户取消请求不适用如果出现网络错误不适用- 否则
执行资源共享检查。如果返回失败,则应用缓存和网络错误步骤。
Yourrequest already fails at the first step of the resource sharing check:
您的请求已在资源共享检查的第一步失败:
- If the response includes zero or more than one
Access-Control-Allow-Origin
header values, return fail and terminate this algorithm.
- 如果响应包含零个或多个
Access-Control-Allow-Origin
标头值,则返回失败并终止此算法。
I provide a simple NodeJS example illustrating your problem.
Your current backend behaves like:
我提供了一个简单的 NodeJS 示例来说明您的问题。
您当前的后端行为如下:
require('http').createServer(function(request, response) {
if (request.method == 'OPTIONS') { // Handle preflight
response.writeHead(200, {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Headers": "X-Foo"
});
} else { // Handle actual requests
response.writeHead(204, {
//"Access-Control-Allow-Origin": "*"
});
}
response.end();
}).listen(12345);
Now, make the request and experience a failure:
现在,发出请求并失败:
var x = new XMLHttpRequest;
x.open('GET', 'http://localhost:12345');
x.setRequestHeader('X-Foo','header to trigger preflight');
x.send();
Go back to the code I provided, and enable the Access-Control-Allow-Origin
header in the response, and test again. Your request will now succeed.
返回我提供的代码,并Access-Control-Allow-Origin
在响应中启用标头,然后再次测试。您的请求现在将成功。