CORS:为啥我的浏览器不发送 OPTIONS 预检请求?

Posted

技术标签:

【中文标题】CORS:为啥我的浏览器不发送 OPTIONS 预检请求?【英文标题】:CORS: Why my browser doesn't send OPTIONS preflight request?CORS:为什么我的浏览器不发送 OPTIONS 预检请求? 【发布时间】:2016-12-09 02:29:01 【问题描述】:

从我读到的关于CORS 的内容,我知道它应该如下工作:

    客户端的脚本尝试从具有不同来源的服务器获取资源。 浏览器拦截此请求并首先向同一 URL 发出 preflight OPTIONS 请求。 如果对这个预检请求的响应包含适当的标头(例如Access-Control-Allow-Origin: *),浏览器就会知道它可以发送主请求并执行它。 响应返回到客户端脚本。

我已经为它设置了一个这样的测试:

Go 中的服务器同时接受 - GET 和 OPTIONS 请求(使用 CURL 检查) - 并在响应中设置 Access-Control-* 标头

简单的 html 页面(由另一个端口上的另一个服务器提供服务),其中包含以下脚本($ 代表 jQuery):

$.ajax(
  type: "GET",
  crossDomain: true,
  url: "http://local.site.com/endpoint,
  success: function (data) 
    alert(data);
  ,
  error: function (request, error) 
    alert(error);
  
);

但是,当我调用此方法时,我在 Chrome 49 和 Firefox 33 的“网络”选项卡中只看到一个 GET 而没有预检 OPTIONS 请求。

以下是我来自 Chrome 的 GET 请求的详细信息:

Accept:*/*
Accept-Encoding:gzip, deflate, sdch
Accept-Language:en-US,en;q=0.8,ru;q=0.6
Connection:keep-alive
Host:local.adform.com
Origin:http://localhost:7500
Referer:http://localhost:7500/test-page.html
User-Agent:Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.87 Safari/537.36

以及相应的回应:

Access-Control-Allow-Headers:Accept, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization
Access-Control-Allow-Methods:POST, GET, OPTIONS, PUT, DELETE
Access-Control-Allow-Origin:*
Content-Length:2
Content-Type:text/plain; charset=utf-8
Date:Wed, 03 Aug 2016 10:53:19 GMT

为什么我的浏览器不发送预检请求有任何想法吗?

【问题讨论】:

预检并不总是完成,不太可能(如果有的话?)使用 GET - 请参阅 documentation 了解何时需要预检 有关浏览器何时发出预检请求的更多信息,请参阅this。 @JaromandaX:谢谢你的评论。如果并不总是需要预检请求,那么克服“同源”政策的(常规)方法是什么?场景是:我们创建一个脚本,该脚本将被合并到第 3 方网站中,并将向我们发送 我们的 cookie?据我了解,没有预检请求浏览器不会将 cookie 发送到我们的服务器,对吧? 请参阅我链接的文档中的下一部分 - request with credentials 我建议您阅读整个页面 - 内容丰富 【参考方案1】:

正如评论员所指出的,使用 GET 浏览器并不总是发送预检 OPTIONS 请求。如果确实需要预检,让浏览器发送它的一种方法是设置自定义标头(例如“X-PINGOVER:pingpong”或其他)。请注意,该服务器还应允许此请求标头,方法是将其添加到“Access-Control-Allow-Headers”响应标头


我的基本目标是将域 a.comcookies 传递到 a.com 的服务器,但从另一个站点的页面 b.com (常见用例是跟踪您在 3rd 方网站上的用户)。事实证明,与请求一起发送 cookie 需要做更多的工作。

客户端(即在 javascript 中)需要启用跨域请求并允许传递凭据。例如。以下 jQuery 请求对我有用:

$.ajax(
  type: "GET",
  url: "http://example.com",
  xhrFields: 
    withCredentials: true           // allow passing cookies
  ,
  crossDomain: true,                // force corss-domain request                
  success: function (data)  ... ,
  error: function (request, error)  ... 
);

服务器端需要设置2个响应头:

Access-Control-Allow-Credentials: true Access-Control-Allow-Origin: <requester origin>

其中<requester origin> 是执行调用的网站的协议+主机+端口。请注意,通用* 可能无法在许多浏览器中工作,因此服务器解析请求的Referer 标头并使用特定允许的来源进行响应是有意义的。

【讨论】:

更多信息请参见MDN Preflight Request docs。 请务必注意,您的服务器可能不会将“X-PINGOVER”作为标头,它可能会返回错误。为了解决这个问题,在您设置Access-Control-Allow-Headers 值的服务器代码中,包括X-PINGOVER

以上是关于CORS:为啥我的浏览器不发送 OPTIONS 预检请求?的主要内容,如果未能解决你的问题,请参考以下文章

CORS 请求 - 为啥不发送 cookie?

HTTP协议详解(HyperText Transfer Protocol 超文本传输协议)访问控制(CORS) (OPTIONS预请求preflight request)浏览器同源策略

在 .NET Core Web API 上为 CORS 启用 OPTIONS 标头

cors / ajax 请求的重复 OPTIONS 请求

为啥我的 Spring 控制器不处理 GraphiQL 发送的 OPTIONS 请求?

CORS Preflight 请求是不是包含请求的标头?