我正在构建一个web API。我发现每当我使用Chrome POST, GET到我的API,总是有一个选项请求发送之前的真正的请求,这是相当恼人的。目前,我让服务器忽略任何OPTIONS请求。现在我的问题是,发送一个OPTIONS请求来增加服务器的负载有什么好处呢?有没有办法完全停止浏览器发送OPTIONS请求?


当前回答

已经讨论过这个问题,下面是我对这个问题的结论和我的解决方案。

根据CORS策略(强烈建议您阅读它),如果浏览器认为它需要停止发送OPTIONS请求,您不能仅仅强制浏览器停止发送OPTIONS请求。

有两种方法可以解决这个问题:

确保你的请求是“简单请求” 设置OPTIONS请求的Access-Control-Max-Age

简单的请求

一个简单的跨站点请求是一个满足以下所有条件的请求:

唯一允许的方法是:

得到 头 帖子

除了由用户代理(例如Connection, user - agent等)自动设置的头信息外,允许手动设置的头信息有:

接受 接收语言 内容语言 内容类型

Content-Type头唯一允许的值是:

应用程序/ x-www-form-urlencoded 多部分/格式 文本/平原

简单的请求不会引起飞行前选项请求。

为OPTIONS检查设置缓存

您可以为OPTIONS请求设置Access-Control-Max-Age,以便它在过期之前不会再次检查权限。

Access-Control-Max-Age给出了在不发送另一个preflight请求的情况下,对preflight请求的响应可以缓存的时间(以秒为单位)。

限制指出

对于Chrome, Access-Control-Max-Age的最大秒数是600,也就是10分钟,根据Chrome源代码 Access-Control-Max-Age每次只对一个资源有效,例如URL路径相同的GET请求,但不同的查询将被视为不同的资源。因此,对第二个资源的请求仍然会触发预飞行请求。

其他回答

编辑2018-09-13:在这个响应的末尾增加了关于这个飞行前请求以及如何避免它的一些精度。

OPTIONS请求是我们在跨源资源共享(CORS)中所谓的飞行前请求。

当您在特定情况下跨不同来源提出请求时,它们是必要的。

某些浏览器会发出这种预运行请求,作为一种安全措施,以确保正在执行的请求是受服务器信任的。 这意味着服务器理解在请求上发送的方法、源和头是安全的。

当您试图执行跨源请求时,您的服务器不应该忽略这些请求,而是应该处理这些请求。

好的资源可以在这里找到http://enable-cors.org/

处理这些问题的一种方法是确保对于任何具有OPTIONS方法的路径,服务器都会发送带有此报头的响应

Access-Control-Allow-Origin: *

这将告诉浏览器服务器愿意回答来自任何来源的请求。

有关如何向服务器添加CORS支持的详细信息,请参阅以下流程图

http://www.html5rocks.com/static/images/cors_server_flowchart.png


编辑2018-09-13

CORS OPTIONS请求仅在某些情况下被触发,如MDN文档中所解释的:

Some requests don’t trigger a CORS preflight. Those are called “simple requests” in this article, though the Fetch spec (which defines CORS) doesn’t use that term. A request that doesn’t trigger a CORS preflight—a so-called “simple request”—is one that meets all the following conditions: The only allowed methods are: GET HEAD POST Apart from the headers set automatically by the user agent (for example, Connection, User-Agent, or any of the other headers with names defined in the Fetch spec as a “forbidden header name”), the only headers which are allowed to be manually set are those which the Fetch spec defines as being a “CORS-safelisted request-header”, which are: Accept Accept-Language Content-Language Content-Type (but note the additional requirements below) DPR Downlink Save-Data Viewport-Width Width The only allowed values for the Content-Type header are: application/x-www-form-urlencoded multipart/form-data text/plain No event listeners are registered on any XMLHttpRequestUpload object used in the request; these are accessed using the XMLHttpRequest.upload property. No ReadableStream object is used in the request.

关于飞行前OPTIONS请求的实际需求,请参考以下答案:CORS -引入飞行前请求的动机是什么?

要禁用OPTIONS请求,ajax请求必须满足以下条件:

请求不设置自定义HTTP报头,如'application/xml'或'application/json'等 请求方法必须是GET、HEAD或POST中的一个。如果是POST,内容类型应该是application/x-www-form-urlencoded、multipart/form-data或text/plain

参考: https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS

在使用代理拦截请求并写入适当的标头的情况下,可以解决这个问题。 在Varnish的特殊情况下,这些将是规则:

if (req.http.host == "CUSTOM_URL" ) {
set resp.http.Access-Control-Allow-Origin = "*";
if (req.method == "OPTIONS") {
   set resp.http.Access-Control-Max-Age = "1728000";
   set resp.http.Access-Control-Allow-Methods = "GET, POST, PUT, DELETE, PATCH, OPTIONS";
   set resp.http.Access-Control-Allow-Headers = "Authorization,Content-Type,Accept,Origin,User-Agent,DNT,Cache-Control,X-Mx-ReqToken,Keep-Alive,X-Requested-With,If-Modified-Since";
   set resp.http.Content-Length = "0";
   set resp.http.Content-Type = "text/plain charset=UTF-8";
   set resp.status = 204;
}

}

我以前用过的一个解决方案——假设你的网站在mydomain.com上,你需要向foreigndomain.com发送一个ajax请求

配置IIS重写从您的域到外部域-例如。

<rewrite>
  <rules>
    <rule name="ForeignRewrite" stopProcessing="true">
        <match url="^api/v1/(.*)$" />
        <action type="Rewrite" url="https://foreigndomain.com/{R:1}" />
    </rule>
  </rules>
</rewrite>

在你的mydomain.com网站上-你可以进行同源请求,不需要任何选项请求:)

不能,但可以使用JSONP避免CORS。