ajax options 禁止_关于http:为什么发送OPTIONS请求,我可以禁用它吗?

我正在构建一个Web API。 我发现每当我使用Chrome进行POST,GET到我的API时,总会在真实请求之前发送OPTIONS请求,这非常烦人。 目前我让服务器忽略任何OPTIONS请求。 现在我的问题是发送OPTIONS请求以加倍服务器负载是什么好事? 有没有办法完全阻止浏览器发送OPTIONS请求?

编辑2018-09-13:增加了关于此飞行前请求的一些准确性以及如何在此响应结束时避免它。

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

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

某些浏览器将此飞行前请求作为安全措施,以确保服务器信任所完成的请求。

这意味着服务器了解在请求上发送的方法,来源和标头是安全的。

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

这里有一个很好的资源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.

我的代码中有以下行,它们支持跨源资源w.Header().Set("Access-Control-Allow-Origin", r.Header.Get("Origin")),w.Header().Set("Access-Control-Allow-Credentials","true"),w.Header().Set("Access-Control-Allow-Methods", r.Header.Get("Access-Control-Request-Method"))和w.Header().Set("Access-Control-Allow-Headers", r.Header.Get("Access-Control-Request-Headers"))。我在我的服务器上有自己的安全检查,所以我不需要OPTIONS请求。我想要做的是从浏览器中禁用它。

您可以通过使用--disable-web-security启动chrome来逃脱它,但我不确定这是否会禁用预检请求。

但是将Chrome标记设置为所有普通用户并不现实。

@ElgsQianChen是true但是浏览器的默认行为。我认为没有办法阻止来自服务器端的预检请求。

为所有用户设置标志是不现实的,但您是唯一一个决定不需要此检查的用户。世界其他地方不知道跨服务器访问的服务器对跨源访问感到满意,直到服务器这样说。关闭与安全相关的设置取决于他们。

在发出跨越原始请求时,要求预检请求是不正确的。只有在特定情况下才需要预检请求,例如,如果您要设置自定义标头,或者提出get,head和post之外的请求。

有趣的是,当使用jQuery发出CORS请求时,JavaScript库特别避免设置自定义标题,并向开发人员发出警告:对于跨域请求,视为预检的条件类似于拼图游戏,我们根本就没有把它确定下来。

@ElgsQianChen - 你还没有接受这个问题的答案,但你的评论表明这个问题解决了你的问题。你能接受吗?这将导致它首先出现在页面上(如果人们将其排序顺序设置为"最新",则首先出现一些不正确且质量较低的答案之前)

如果我对它运行的api curl怎么办,但是当从chrome运行时我得到错误?

@SuperUberDuper因为CORS和预检请求是浏览器相关的事情。您可以通过在请求中添加Origin标头来模拟CORS,以模拟请求来自特定主机(例如yourwebsite.com)。您还可以通过将请求的HTTP方法设置为OPTIONS和Access-Control-*标头来模拟预检请求

@LeoCorrea因为您的问题在SO和Google上很受欢迎,所以我已经更新了答案,其中包含了一些关于浏览器未发送飞行前请求的准确性,2018年;)

您添加的标头:DPR, Downlink, Save-Data, Viewport-Width, Width来自Mozilla开发人员,特定于Mozilla。 Chromium可能有其他想法。在一天结束时,它们没有记录,并且未被IETF和W3C列入当前标准,因此我不会将它们列入列表中。

说"CORS OPTIONS请求仅在某些情况下被触发"对于Web应用程序用例来说是一种粗略的低估。您很少会在没有Authorization标头和/或使用application/json作为内容类型的情况下发送API请求,这意味着有时不需要OPTIONS请求,它们几乎总是需要它们。在数据繁重的Web应用程序中,这意味着您当前必须从与应用程序相同的主机提供API以避免OPTIONS请求,这是一个遗憾,因为有许多用例可以让不同的主机有意义。

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

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

有两种方法可以解决它:

确保您的请求是"简单请求"

为OPTIONS请求设置Access-Control-Max-Age

简单的要求

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

唯一允许的方法是:

得到

POST

除了由用户代理自动设置的标头(例如,连接,用户代理等)之外,允许手动设置的唯一标头是:

接受

接受语言

内容语言

内容类型

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

应用程序/ x-WWW窗体-urlencoded

多部分/格式数据

纯文本/

简单的请求不会导致飞行前的OPTIONS请求。

为OPTIONS检查设置缓存

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

Access-Control-Max-Age gives the value in seconds for how long the response to the preflight request can be cached for without sending another preflight request.

限制注意到

对于Chrome,根据Chrome源代码,Access-Control-Max-Age的最大秒数为600,即10分钟

Access-Control-Max-Age每次仅适用于一个资源,例如,GET请求具有相同的URL路径但不同的查询将被视为不同的资源。因此,对第二个资源的请求仍将触发预检请求。

IMO,这是这个帖子中最清晰的答案。

是的......这应该是接受的答案,与问题最相关..!

谢谢你提到Access-Control-Max-Age。这是关键所在。它可以帮助您避免过多的预检请求。

我正在使用axios来调用get请求。我在哪里可以在axios请求中设置Access-Control-Max-Age?

+1 Access-Control-Max-Age标头是此处的关键。这应该是公认的答案!我在标题上设置了86400秒(24小时),预先请求消失了!

说我们永远不应该使用application/json是正确的,因为OPTIONS会慢一些吗?

谢谢,好的。如果我们将缓存长时间设置为8小时,是否存在任何安全问题?

@VitalyZdanevich不!不要因为它使您的请求非"简单"(因此触发CORS)而避免application/json。浏览器正在完成它的工作。将服务器设置为返回类似Access-Control-Max-Age: 86400的标题,浏览器将不会重新发送OPTIONS请求24小时。

@colminator取决于您使用的浏览器,Chromium将其限制为10分钟,请参阅cs.chromium.org/chromium/src/services/network/public/cpp/cors/…

如果严格遵循此规范,因为只有GET,HEAD和POST请求是"简单的",预检OPTIONS请求是否应该需要自己的预检请求(无限期)?

请参考这个答案,了解预先确定的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

+1"自定义HTTP标头"!就我而言,他们导致了飞行前的请求被触发。当请求主体和OPTIONS请求停止发送时,我重构了发送在头中发送的任何内容的请求。

application/xml或application/json不是"自定义HTTP标头"。标题本身将是Content-Type并且调用该标题"custom"会产生误导。

删除了自定义HTTP标头,这就像一个魅力!

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

哦,我在想什么。调试几个小时这是我的解决方案。由于调试控制台而禁用缓存。

即使调试控制台已关闭,也会发送预检请求

Luca:这是真的,但关键是当关闭开发工具时"禁用缓存"没有效果。如果未禁用缓存,则预检请求仅发送一次(当然是每台服务器),并且如果禁用缓存,则在每个请求之前发送预检请求。

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

看看这里:

https://github.com/jpillora/xdomain

工作实例:

http://jpillora.com/xdomain/

这实际上是一种插入式代理吗?

"当您将任何数据发送(发布)到另一个域时,选项请求是一个预检请求。" - 这不是真的。您可以使用XHR发送可以使用普通HTML表单发送的任何POST请求,而不会触发预检请求。只有当您开始执行表单无法执行的操作(如自定义内容类型或额外请求标头)时,才会发送预检。

这里的解决方案似乎依赖于iframe垫片,它在某些情况下有效,但有一些主要的局限性。如果您想知道响应的HTTP状态代码或另一个HTTP响应头的值,会发生什么?

iFrames不是为此而制作的。

这是一个软件实现,它确实回答了最后一个问题:"有没有办法完全阻止浏览器发送OPTIONS请求?"。简而言之,没有办法在Mozilla或Chromium中禁用它,它在代码中实现,唯一的"工作"选项只是绕过行为。

对于了解其存在的原因但需要访问不使用auth处理OPTIONS调用的API的开发人员,我需要一个临时答案,以便我可以在本地开发,直到API所有者添加适当的SPA CORS支持或我获得代理API启动并运行。

我发现你可以在Safari上禁用CORS,在Mac上禁用Chrome。

在Chrome中停用相同的来源政策

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

Safari:在Safari中禁用同源策略

If you want to disable the same-origin policy on Safari (I have 9.1.1), then you only need to enable the developer menu, and select"Disable Cross-Origin Restrictions" from the develop menu.

你应该把更多的亮点放在"永远不应该是永久解决方案!!!!"的部分。同源策略是一项非常重要的浏览器安全措施,在正常浏览互联网时绝不应禁用。

我希望网络能够以这种方式工作,因此我们可以直接从服务器请求数据,而无需额外的麻烦。

正如之前的帖子中所提到的,OPTIONS请求是有原因的。如果您的服务器响应时间很长(例如海外连接),您也可以让浏览器缓存预检请求。

让您的服务器使用Access-Control-Max-Age标头回复,对于转到同一端点的请求,预检请求将被缓存而不再发生。

这次真是万分感谢!在我阅读的所有CORS文档中,OPTIONS请求将使用此标头缓存的事实是非常不透明的。

缓存只对完全相同的URL生效。我想要一个域级预检缓存,它可以真正减少往返次数。 (CORS很傻!)

我已经解决了这个问题。

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();

}

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

你不能但是你可以使用JSONP来避免使用CORS。

如果您做的事情不简单,您只会收到OPTIONS请求。您只能使用JSONP发出简单请求(GET,没有自定义标头,没有身份验证数据),因此JSONP无法替代此处。

是的,我知道,但我不知道确切的项目要求。我知道这不是简单的避免,但它取决于项目。在最糟糕的情况下,为了避免使用CORS,您需要使用get参数传递数据。因此,JSONP可以根据项目要求替换cors(正如您所说,使用简单的请求)

我不明白所谓的飞行前的设计。如果客户决定将数据发送到服务器,会导致它不安全的原因是什么?我认为将电线上的负载加倍是没有任何意义的。

@ElgsQianChen这可以回答你的问题stackoverflow.com/questions/15381105/…

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

我的Web API项目设置如下:

// WebApiConfig.cs

public static void Register(HttpConfiguration config)

{

var cors = new EnableCorsAttribute("*","*","*");

config.EnableCors(cors);

//...

}

我在web.config> system.webServer节点中没有像我在很多帖子中看到过的CORS特定配置选项

global.asax或控制器中没有CORS特定代码作为装饰器

问题是应用程序池设置。

托管管道模式设置为classic(将其更改为集成),Identity设置为Network Service(将其更改为ApplicationPoolIdentity)

更改这些设置(并刷新应用程序池)为我修复了它。

对我有用的是导入"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就会始终添加Content-Type标头,这不在我以前的AllowedHeaders配置中。

在使用拦截请求并写入适当头的代理的情况下,可以解决这个问题。

在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重写 - 例如

在你的mydomain.com网站上 - 你可以提出相同的原始请求,并且不需要任何选项请求:)

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

如果找到一些时间,我会测试并更新这篇文章!

CSP:https://developer.mozilla.org/fr/docs/Web/HTTP/Headers/Content-Security-Policy

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

我刚刚测试过它不起作用,在CSP for xhr请求录入后仍然需要CORS ...

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值