为什么Chrome取消了CORS OPTIONS请求

17
在我的应用中,我正在从HTTP创建AJAX请求到HTTPS。这意味着我需要CORS。因此,我向jQuery.ajax添加了一些标头和参数并进行测试。在Firefox中一切正常,但在Chrome中不行。Chrome会“杀死”每个预检请求(OPTIONS)。
jQuery脚本:
$(document).on('click', 'a.ajax', function(e) {
    e.preventDefault();
    $.ajax(this.href, {
        type: 'GET',
        dataType: 'json',
        crossDomain: false,
        headers: {'X-Requested-With': 'XMLHttpRequest'},
        xhrFields: {
            withCredentials: true
        }
    });
    return false;
});

HTTP转储:

> OPTIONS /foo HTTP/1.1
> User-Agent: curl/7.29.0
> Host: local.bar.cz
> Accept: */*
> Access-Control-Request-Headers:accept, origin, x-requested-with
> Access-Control-Request-Method:GET
> Origin:http://local.bar.cz
> 
< HTTP/1.1 204
< Server: nginx/1.2.7
< Date: Wed, 27 Feb 2013 15:06:54 GMT
< Content-Type: text/html; charset=utf-8
< Connection: keep-alive
< X-Powered-By: Nette Framework
< X-Frame-Options: SAMEORIGIN
< Access-Control-Allow-Origin: http://local.bar.cz
< Access-Control-Allow-Credentials: true
< Access-Control-Allow-Headers: accept, origin, x-requested-with
< Access-Control-Allow-Methods: OPTIONS, GET, POST, HEAD
< 

任何人都知道为什么Chrome终止了这个请求吗?

Chrome “kills” the request是什么意思?如果您在Chrome的控制台和网络选项卡中查看请求,会看到什么错误?实际请求是否正在进行,还是预检失败了? - monsur
在Chrome的控制台中的网络选项卡中,我有一个状态为“(已取消)”的预检请求(OPTIONS)。 - Patrik Votoček
尝试清除您的 X-Requested-With 字段,将其设置为 ""。 - Rishi Diwan
3个回答

18

可能你的https服务器使用了不受信任的证书。如果是这样的话,请先在浏览器中访问该URL,并接受不受信任的连接。


1
这正是情况所在。我有相同的情况 - 使用虚拟自签名证书的NodeJS服务器。在我在浏览器中打开URL后,一切都很顺利,Chrome停止取消我的OPTIONS请求。 - ytropek
2
顺便提一下,小心使用CORS、自签名证书和Google Chrome/Chromium。我刚刚因为这个问题浪费了整个上午:https://code.google.com/p/chromium/issues/detail?id=141839 - Chris Allen Lane

12

接受证书并不能总是解决这个问题。如果您使用自签名证书,即使您首先接受它,Chrome 在某些情况下仍会取消您的预检 OPTIONS 请求。自2011年以来就一直如此:

如该页面中所述的解决方法是将自签名证书添加到您系统的受信任证书列表中。

在 Mac 上执行以下操作(根据原始说明进行了轻微修改,以便在 OS 10.8.5 中使用 http://www.robpeck.com/2010/10/google-chrome-mac-os-x-and-self-signed-ssl-certificates/):

  1. 在地址栏中,单击带有 X 的小锁。这将弹出一个小信息窗口。
  2. 单击“证书信息”按钮。
  3. 点击并拖动证书图像到打开的 Finder 窗口中(好像无法拖到桌面)。
  4. 双击创建的文件。这将打开密钥串访问实用程序。输入密码以解锁它。
  5. 确保将证书添加到“系统”密钥串,而不是“登录”密钥串。单击“始终信任”,尽管这似乎没有做什么。
  6. 添加后,再次双击它。您可能需要再次进行身份验证。
  7. 展开“信任”部分。将“When using this certificate”设置为“始终信任”

您可能需要重新启动 Chrome 才能完全信任该证书(图标变成了一个快乐的绿色锁,出现在 URL 栏中)。


9
值得一提的是,还有另一种情况会产生完全相同的结果:
如果在等待请求返回时(通过promise),将浏览器重定向到不同的URL(window.location ..),则OPTIONS请求将被提交,但随后的响应(POST / GET / *)将被取消(自然..)
是的..当然..如果你这样做,那么这是一个错误..但它可能看起来完全相同,并且会花费数小时查找错误。
考虑以下代码:
makeAjaxCallThatReturnsAPromise.then(
    function () { // doSomething },
    function () { // doSomethingElse }
);
location.replace('http://some.where/');

1
我必须说,这个CORS失败真的是一个真正的睡客。它确实从未被提及过,而在阅读本文之前,我已经花费了令人尴尬的时间来解决它。由于时间问题,当然,我们无法控制,这就是问题所在。我在我的ajax POST之前更改了window.location页面,并且一直失败。阅读了这篇答案后,我将window.location语句移动到了我的$.post语句的success:代码中,并且它起作用了。如果所有其他事情都已经验证过了,那么这一点必须被检查!非常有帮助!+1 - Ric

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接