Javascript 当后续请求的答案为204时,为什么选项请求失败?

Javascript 当后续请求的答案为204时,为什么选项请求失败?,javascript,ajax,backbone.js,xmlhttprequest,cors,Javascript,Ajax,Backbone.js,Xmlhttprequest,Cors,我正在构建一个基于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. 好吧,CORS

我正在构建一个基于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.
好吧,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
看起来不错,现在可以得到:

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
如果我请求至少包含一个对象的boots集合,则一切正常。我的服务器用arr响应CORS头,正如我所想的那样,完全正常。那么为什么浏览器会报告跨源资源问题呢

这是因为我的204个回复的内容类型
text/plain

开发工具中的飞行前(选项)请求:

中止响应的请求头:

您还必须在第二个请求的响应头中包含
访问控制允许来源。这不是客户端问题,而是后端问题

该行为符合以下解释()中应用的:

  • 飞行前请求(省略)
  • “将设置为飞行前完成。”
  • “这是实际请求。(……)在发出请求时请遵守以下请求规则。”
    • 如果响应的HTTP状态代码为301、302、303或307,则不适用
    • 如果最终用户取消请求,则不适用
    • 如果存在网络错误,则不适用
    • 否则
      执行一项任务。如果返回fail,则应用缓存和网络错误步骤
  • 您的请求已在以下步骤的第一步失败:

  • 如果响应包含零个或多个
    Access Control Allow Origin
    头值,则返回fail并终止此算法

  • 我提供一个简单的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);
    
    现在,提出请求并经历一次失败

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

    返回到我提供的代码,在响应中启用
    访问控制允许原点
    标题,然后再次测试。您的请求现在将成功。

    确保问题确实是由CORS引起的,而不是服务器端故障。使用
    --disable web security
    标志运行Chrome,并仔细检查服务器的响应。不幸的是,OSX上最新的Chrome(非开发)在使用该命令行开关启动时死亡。请检查服务器的错误日志。Serverlog正常:started GET“/v1/foos/00000d/bar/000014/boots”对于2012-11-10 11:33:04+0100的93.219.xxx.yyy,V1::BootsController将索引作为JSON参数进行处理:{“foo_id”=>“00000d”,“bar_id”=>“000014”}呈现的文本模板(0.0ms)在7ms内完成了204个内容(视图:0.4ms),因此,服务器不是问题的原因。204根本不包括CORS头。。。谢谢你的努力和伟大的答案!