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


当前回答

在使用代理拦截请求并写入适当的标头的情况下,可以解决这个问题。 在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;
}

}

其他回答

编辑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.

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

根据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请求,但不同的查询将被视为不同的资源。因此,对第二个资源的请求仍然会触发预飞行请求。

你也可以使用API管理器(如开源的Gravitee.io)通过在preflight中操作头来防止前端应用程序和后端服务之间的CORS问题。

用于响应preflight请求的报头,以指示在发出实际请求时可以使用哪些HTTP报头:

内容类型 access-control-allow-header 授权 x-requested-with

并指定"allow-origin" = localhost:4200

在使用代理拦截请求并写入适当的标头的情况下,可以解决这个问题。 在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;
}

}

在花了一整天半的时间试图解决类似的问题后,我发现这与IIS有关。

我的Web API项目是这样建立的:

// WebApiConfig.cs
public static void Register(HttpConfiguration config)
{
    var cors = new EnableCorsAttribute("*", "*", "*");
    config.EnableCors(cors);
    //...
}

我在网上没有CORS特定的配置选项。配置>系统。webServer节点,就像我在很多帖子中看到的那样

全局中没有特定于CORS的代码。Asax或在控制器中作为装饰器

问题在于应用程序池设置。

托管管道模式被设置为经典(更改为集成),标识被设置为网络服务(更改为ApplicationPoolIdentity)

更改这些设置(并刷新应用程序池)为我解决了这个问题。