当后续请求的答案是204时,为什么OPTIONS请求失败?

Geo*_*ieF 6 javascript ajax xmlhttprequest cors backbone.js

我正在构建一个基于Backbone.js的应用程序并面临一个奇怪的问题.

在某个时刻,应用程序请求收集资源,在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.
Run Code Online (Sandbox Code Playgroud)

好吧,我认为CORS问题并归咎于我的API.然后通过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
Run Code Online (Sandbox Code Playgroud)

看起来不错,现在是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
Run Code Online (Sandbox Code Playgroud)

如果我请求包含至少一个对象的靴子集合,一切正常.我认为,我的服务器响应arr完全正常的CORS标头.那么为什么浏览器报告跨源资源问题呢?

是由于text/plain我的204回复的内容类型?

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

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

Rob*_*b W 12

您还必须Access-Control-Allow-Origin在第二个请求的响应头中包含该内容.这不是客户端问题,而是后端问题.

此行为符合CORS规范,适用于以下说明(第7.1.5节"带预检的跨源请求"):

  1. 预检请求(详情略去)
  2. "将跨源请求状态设置为预检完成."
  3. "这是实际请求.(...)在提出请求时遵守以下请求规则."
    • 如果响应的HTTP状态代码为301,302,303或307 不适用
    • 如果最终用户取消请求 不适用
    • 如果存在网络错误 不适用
    • 否则
      执行资源共享检查.如果它返回失败,请应用缓存和网络错误步骤.

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

  1. 如果响应包含零个或多个Access-Control-Allow-Origin标头值,则返回失败并终止此算法.

我提供了一个简单的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);
Run Code Online (Sandbox Code Playgroud)

现在,提出请求并体验失败:

var x = new XMLHttpRequest;
x.open('GET', 'http://localhost:12345');
x.setRequestHeader('X-Foo','header to trigger preflight');
x.send();
Run Code Online (Sandbox Code Playgroud)

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