为什么发送OPTIONS请求,我可以禁用它吗?

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

601429 次浏览

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

OPTIONS请求就是我们在Cross-origin resource sharing (CORS)中所称的pre-flight请求。

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

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

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

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

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

# EYZ0

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

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

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

CORS流程图


编辑2018-09-13

CORS OPTIONS请求只在某些情况下被触发,正如MDN文档所解释的那样:

有些请求不会触发CORS的飞行前准备。在本文中,这些请求被称为“简单请求”,尽管Fetch规范(定义了CORS)没有使用这个术语。一个不触发CORS预飞的请求,即所谓的“简单请求”,是一个满足以下所有条件的请求:

唯一允许的方法是:

  • 得到
  • 帖子

除了用户代理自动设置的报头(例如,Connection, user - agent,或任何其他在Fetch规范中定义为“禁止报头名称”的报头),唯一允许手动设置的报头是那些Fetch规范定义为“CORS-safelisted请求报头”的报头,它们是:

  • 接受
  • 接收语言
  • 内容语言
  • 内容-类型(但请注意下面的附加要求)
  • DPR
  • 下行
  • 保存数据
  • Viewport-Width
  • 宽度

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

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

请求中使用的任何XMLHttpRequestUpload对象上都没有注册事件侦听器;这些是使用XMLHttpRequest访问的。上传的财产。

请求中没有使用ReadableStream对象。

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

是的,有可能避免期权请求。选项请求是一个飞行前请求,当你发送(post)任何数据到另一个域。这是浏览器安全问题。但是我们可以使用另一种技术:iframe传输层。我强烈建议您忘记任何CORS配置,并使用现成的解决方案,它将在任何地方工作。

看这里: # EYZ0 < / p >

和工作示例: # EYZ0 < / p >

请参考实际需要的预飞行选项请求的答案:CORS -引入飞行前请求的动机是什么?

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

  1. 请求不设置自定义HTTP报头,如'application/xml'或'application/json'等
  2. 请求方法必须是GET、HEAD或POST中的一个。如果是POST,内容类型应该是application/x-www-form-urlencodedmultipart/form-datatext/plain之一
< p >参考: # EYZ0 < / p >

正如在之前的文章中提到的,OPTIONS请求的存在是有原因的。如果您的服务器响应时间过长(例如海外连接),您也可以让浏览器缓存飞行前请求。

让您的服务器回复Access-Control-Max-Age头,并且对于到达同一端点的请求,preflight请求将被缓存,不再发生。

当您打开调试控制台并打开Disable Cache选项时,将始终发送预飞行请求(即在每个请求之前)。如果不禁用缓存,预运行请求将只发送一次(每个服务器)。

我已经解决了这个问题。

if($_SERVER['REQUEST_METHOD'] == 'OPTIONS' && ENV == 'devel') {
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Headers: X-Requested-With');
header("HTTP/1.1 200 OK");
die();
}

这只是为了发展。这样我就可以等待9毫秒和500毫秒,而不是8秒和500毫秒。我可以这样做,因为生产JS应用程序将在同一台机器上生产,所以不会有OPTIONS,但开发是我的本地。

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

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

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

  1. 确保你的请求是“简单请求”
  2. 为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,根据Chrome源代码,这是10分钟
  • Access-Control-Max-Age每次只对一个资源有效,例如,GET请求具有相同的URL路径,但不同的查询将被视为不同的资源。因此,对第二个资源的请求仍然会触发预飞行请求。

对于一个理解它存在的原因,但需要访问一个没有认证就不能处理OPTIONS调用的API的开发人员,我需要一个临时的答案,这样我就可以在本地开发,直到API所有者添加适当的SPA CORS支持或我获得一个代理API并运行。

我发现你可以在Mac电脑的Safari和Chrome浏览器中禁用CORS。

在Chrome中禁用同源策略

Chrome浏览器:退出Chrome浏览器,打开终端并粘贴如下命令:open /Applications/Google\ Chrome.app --args --disable-web-security --user-data-dir

Safari: # EYZ0

如果你想在Safari上禁用同源策略(我有9.1.1),那么你只需要启用开发人员菜单,并从开发菜单中选择“禁用跨源限制”。

对我有用的是导入“github.com/gorilla/handlers”,然后这样使用它:

router := mux.NewRouter()
router.HandleFunc("/config", getConfig).Methods("GET")
router.HandleFunc("/config/emcServer", createEmcServers).Methods("POST")


headersOk := handlers.AllowedHeaders([]string{"X-Requested-With", "Content-Type"})
originsOk := handlers.AllowedOrigins([]string{"*"})
methodsOk := handlers.AllowedMethods([]string{"GET", "HEAD", "POST", "PUT", "OPTIONS"})


log.Fatal(http.ListenAndServe(":" + webServicePort, handlers.CORS(originsOk, headersOk, methodsOk)(router)))

一旦我执行了Ajax POST请求并将JSON数据附加到它,Chrome总是会添加内容类型头,这不是在我以前的AllowedHeaders配置。

我以前用过的一个解决方案——假设你的网站在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网站上-你可以进行同源请求,不需要任何选项请求:)

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

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

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

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

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

问题出在应用池设置上。

管理管道模式设置为经典(改成集成了), 身份设置为网络服务(改为ApplicationPoolIdentity)

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

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

也许有一个解决方案(但我没有测试它):你可以使用CSP(内容安全策略)来启用你的远程域,浏览器可能会跳过CORS OPTIONS请求验证。

如果我有时间的话,我会测试一下并更新这篇文章!

CSP: # eyz0

CSP规格:https://www.w3.org/TR/CSP/

OPTIONS请求是web浏览器的一个特性,所以要禁用它并不容易。但我找到了一种方法,用<强> < /重定向强>来消除它。如果服务端点还不能处理CORS/OPTIONS,可能还在开发中,或者配置错误,那么它就很有用。

步骤:

  1. 使用工具(nginx, YARP,…)为这些请求设置反向代理。
  2. 创建一个端点来处理OPTIONS请求。创建一个普通的空端点可能更容易,并确保它能很好地处理CORS。
  3. 为代理配置两组规则。一种是将所有OPTIONS请求路由到上面的虚拟端点。另一个是将所有其他请求路由到实际的问题端点。
  4. 更新网站以使用代理代替。

基本上这种方法是欺骗浏览器,选项请求工作。考虑到CORS并不是为了加强安全,而是为了放松同源政策,我希望这招能管用一段时间。:)