CORS:预检通过,主请求完成 w/200,但浏览器仍然有 Origin 错误

Posted

技术标签:

【中文标题】CORS:预检通过,主请求完成 w/200,但浏览器仍然有 Origin 错误【英文标题】:CORS: preflight passes, main request completes w/200, but browser still has Origin error 【发布时间】:2013-06-25 15:43:30 【问题描述】:

我正在向运行 express 的节点服务器发送 CORS ajax 请求。在服务器日志和 js 控制台中,我可以看到预检 OPTIONS 请求成功。

然后,主请求也在服务器上成功并以 200 和我认为正确的标头响应。但是,在 Chrome 中,网络选项卡将后一个请求报告为“已取消”,并且不接受或处理响应:

XMLHttpRequest 无法加载 http://myserver.com/upload。 Access-Control-Allow-Origin 不允许来源http://mysite.com。

这里是打印出请求和响应标头的服务器日志:

76.79.201.210 - - [27/Jun/2013:23:23:17 +0000] "OPTIONS /upload HTTP/1.1" 204 0 "http://mysite.com/add" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_4) AppleWebKit/537.36 (Khtml, like Gecko) Chrome/27.0.1453.116 Safari/537.36"
START
 host: 'localhost:5001',
  connection: 'close',
  'content-length': '109587',
  origin: 'http://mysite.com',
  'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.116 Safari/537.36',
  'content-type': 'multipart/form-data; boundary=----WebKitFormBoundaryBZA4TATeeVWMHArH',
  accept: '*/*',
  referer: 'http://mysite.com/add',
  'accept-encoding': 'gzip,deflate,sdch',
  'accept-language': 'en-US,en;q=0.8' 
 'x-powered-by': 'Express',
  'access-control-allow-origin': '*',
  'access-control-allow-methods': 'GET, POST, PUT, DELETE, OPTIONS',
  'access-control-allow-headers': 'X-Requested-With' 
XX.XX.XXX.210 - - [27/Jun/2013:23:23:19 +0000] "POST /upload HTTP/1.1" 200 118 "http://mysite.com/add" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.116 Safari/537.36"
- - - [Thu, 27 Jun 2013 23:23:19 GMT] "POST /upload HTTP/1.0" 200 - "http://mysite.com/add" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.116 Safari/537.36"

更新:Chrome 网络标签的屏幕截图——“已取消”的截图是 200 以上的截图

http://cl.ly/image/3c09330i1a17

【问题讨论】:

我也尝试将“Access-Control-Allow-Headers”设置为“*”,结果相同 您在实际请求中设置了 CORS 标头,对吗?不仅仅是预检? 是的,上面的第二组标头(以 x-powered-by 开头)是主要响应的标头。我没有打印出选项请求标头,但它们是相同的。 我在使用 Spring Boot 服务器时遇到了同样的问题,并为它提供了不同的解决方案。 (我知道这个问题很老了)对我来说,这是因为我在请求中使用了expired access token。而不是拒绝访问,我在预检中得到了 200,并且出现了缺少访问允许标头的 CORS 错误。使用有效的 baerer 令牌后,它起作用了。 【参考方案1】:

解决 CORS 相关问题

如果您尝试重现问题,但没有看到请求/响应,可能是您的浏览器缓存了先前失败的预检请求尝试。清除浏览器的缓存也可能会清除预检缓存...

https://developers.google.com/storage/docs/cross-origin

我在test-cors.org 上测试了以下配置,它似乎可以工作。请记住在进行故障排除时不时清除缓存。

var allowedHost = 
    // this is the origin that test-cors.org uses
    'http://client.cors-api.appspot.com': true
;

var allowCrossDomain = function(req, res, next) 
    if (!req.headers.origin || allowedHost[req.headers.origin]) 
        res.header('Access-Control-Allow-Credentials', true);
        res.header('Access-Control-Allow-Origin', req.headers.origin)
        res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS');
        res.header('Access-Control-Allow-Headers', 'X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Content-Length, Content-MD5, Content-Type, Date, X-Api-Version');
        if (req.method == 'OPTIONS') res.send(200);
        else next();
    
    else 
        res.send(403, 
            auth: false
        );
    

祝你好运!

【讨论】:

这个日志和那个“localhost”实际上是在服务器本身上,它有自己的域,所以 Chrome 实际上是在与 myserver.com/upload 对话,而不是 localhost:5001/upload跨度> 谢谢 - 不过还是没有运气,或者使用 Access-Control-Allow-Headers:* 感谢有关预检缓存的信息。【参考方案2】:

事实证明,因为我同时设置了 nginx 和 express 来响应选项请求的标头,它以某种方式将 Access-Control-Allow-Origin 标头值组合到“”、“ em>”。我不知道它是把它读成数组还是什么。

仍然很困惑,因为 1) 为什么请求会通过 nginx?以及 2) 如果 OPTIONS 标头搞砸了,为什么浏览器会继续执行 POST?

哦,好吧,一如既往的教训——不要重复自己。

【讨论】:

Chrome 中可能存在一个错误(?),无论 OPTIONS 的结果如何,都会继续发布帖子。我得到了 405s 并且仍然通过 POST。显然,让它正常工作是困难

以上是关于CORS:预检通过,主请求完成 w/200,但浏览器仍然有 Origin 错误的主要内容,如果未能解决你的问题,请参考以下文章

CORS预检请求被阻止.Net Core 2.2 [重复]

CORS 请求已预检,但似乎不应该

预检浏览器请求期间的 CORS 问题 [重复]

如何处理无效的 CORS 预检请求?

Twitter API 授权在浏览器中未通过 CORS 预检

在 node/express 中启用了 CORS,但得到“对预检请求的响应未通过访问控制检查”