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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-26 18:25:19  来源:igfitidea点击:

Why does an OPTIONS request fail when the answer to the follow up request is a 204?

javascriptajaxbackbone.jsxmlhttprequestcors

提问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/plainof my 204 responses?

是不是因为text/plain我的 204 响应的内容类型?

Preflight (OPTIONS) request in dev tools: OPTIONS

开发工具中的预检(选项)请求: 选项

Request headers of aborted response: GET

中止响应的请求标头: 得到

回答by Rob W

You have to also include the Access-Control-Allow-Originin 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 节“带有预检的跨域请求”):

  1. Preflight request (detailsomitted)
  2. "Set the cross-origin request statusto preflight complete."
  3. "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 applicable
    • If the end user cancels the requestNot applicable
    • If there is a network errorNot applicable
    • Otherwise
      Perform a resource sharing check. If it returns fail, apply the cache and network error steps.
  1. 预检请求(细节省略)
  2. “将跨域请求状态设置为预检完成。”
  3. “这是实际的请求。(...)在提出请求时遵守下面的请求规则。”
    • 如果响应的 HTTP 状态代码为 301、302、303 或 307不适用
    • 如果最终用户取消请求不适用
    • 如果出现网络错误不适用
    • 否则
      执行资源共享检查。如果返回失败,则应用缓存和网络错误步骤。

Yourrequest already fails at the first step of the resource sharing check:

您的请求已在资源共享检查的第一步失败:

  1. If the response includes zero or more than one Access-Control-Allow-Originheader values, return fail and terminate this algorithm.
  1. 如果响应包含零个或多个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-Originheader in the response, and test again. Your request will now succeed.

返回我提供的代码,并Access-Control-Allow-Origin在响应中启用标头,然后再次测试。您的请求现在将成功。