Answers:
编辑2018-09-13:在此预检请求以及在此响应结束时如何避免它方面增加了一些精度。
OPTIONS
请求就是我们在中所称的pre-flight
请求Cross-origin resource sharing (CORS)
。
当您在特定情况下跨不同来源发出请求时,它们是必需的。
某些浏览器会发出此飞行前请求,作为一种安全措施,以确保服务器信任正在执行的请求。意味着服务器了解请求上发送的方法,源和标头是安全的。
每当您尝试进行跨源请求时,服务器都不应忽略,而应处理这些请求。
一个很好的资源可以在这里找到http://enable-cors.org/
处理这些问题的一种方法是确保对于OPTIONS
方法的任何路径,服务器使用此标头发送响应
Access-Control-Allow-Origin: *
这将告诉浏览器服务器愿意回答任何来源的请求。
有关如何向服务器添加CORS支持的更多信息,请参见以下流程图
http://www.html5rocks.com/static/images/cors_server_flowchart.png
编辑2018-09-13
OPTIONS
仅在某些情况下触发CORS 请求,如MDN docs中所述:
有些请求不会触发CORS预检。尽管Fetch规范(定义了CORS)未使用该术语,但在本文中将其称为“简单请求”。不会触发CORS预检的请求(所谓的“简单请求”)是满足以下所有条件的请求:
唯一允许的方法是:
- 得到
- 头
- 开机自检
除了由用户代理自动设置的标头(例如,Connection,User-Agent或在Fetch规范中定义为“禁止标头名”的任何其他标头)外,仅允许将标头手动设置的是Fetch规范定义为“ CORS安全列出的请求标头”的设置,它们是:
- 接受
- 接受语言
- 内容语言
- 内容类型(但请注意以下其他要求)
- DPR
- 下行链接
- 保存数据
- 视口宽度
- 宽度
Content-Type标头的唯一允许值为:
- 应用程序/ x-www-form-urlencoded
- 多部分/表单数据
- 文字/纯文字
没有在请求中使用的任何XMLHttpRequestUpload对象上注册事件侦听器;这些可以使用XMLHttpRequest.upload属性访问。
请求中未使用ReadableStream对象。
curl
对它起作用的api 怎么做,但是从chrome运行时出现错误?
Origin
在请求中添加标头来模拟CORS,以模拟该请求,就像请求来自特定主机(例如yourwebsite.com)一样。您也可以通过设置到请求的HTTP方法模拟预检要求OPTIONS
和Access-Control-*
头
经历了这个问题之后,下面是我对该问题的总结和解决方案。
根据CORS策略(强烈建议您阅读它),您不能仅仅强迫浏览器认为有必要就停止发送OPTIONS请求。
有两种解决方法:
Access-Control-Max-Age
为OPTIONS请求设置一个简单的跨站点请求是满足以下所有条件的请求:
唯一允许的方法是:
除了由用户代理自动设置的标头(例如,Connection,User-Agent等)之外,唯一允许手动设置的标头是:
Content-Type标头的唯一允许值为:
一个简单的请求不会导致飞行前OPTIONS请求。
您可以Access-Control-Max-Age
为OPTIONS请求设置一个,以便它在到期之前不会再次检查该权限。
Access-Control-Max-Age提供以秒为单位的值,该值表示可以在不发送其他预检请求的情况下将对预检请求的响应进行缓存的时间。
Access-Control-Max-Age
就是600
其为10分钟,根据铬源代码Access-Control-Max-Age
每次仅对一种资源起作用,例如,GET
具有相同URL路径但不同查询的请求将被视为不同资源。因此,对第二个资源的请求仍将触发预检请求。Access-Control-Max-Age
。这就是关键。它可以帮助您避免过多的预检请求。
application/json
仅仅因为它使您的请求变得“简单”(从而触发CORS)就回避。浏览器正在执行其工作。将您的服务器设置为返回标头之类的内容Access-Control-Max-Age: 86400
,浏览器将在24小时内不重新发送OPTIONS请求。
请根据实际的预检选项请求参考此答案:CORS-引入预检请求的动机是什么?
要禁用OPTIONS请求,必须满足ajax请求的以下条件:
application/x-www-form-urlencoded
,multipart/form-data
或text/plain
参考:https : //developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS
application/xml
或application/json
不是“自定义HTTP标头”。标头本身就是这样,Content-Type
并且将标头称为“自定义”将产生误导。
是的,可以避免选择要求。当您将任何数据发送(发布)到另一个域时,选项请求是预检请求。这是浏览器的安全问题。但是我们可以使用另一种技术:iframe传输层。我强烈建议您忘记任何CORS配置并使用现成的解决方案,它可以在任何地方使用。
在这里看看:https : //github.com/jpillora/xdomain
工作示例:http : //jpillora.com/xdomain/
对于了解其存在原因但需要访问未经身份验证即无法处理OPTIONS调用的API的开发人员,我需要一个临时答复,以便可以在本地进行开发,直到API所有者添加适当的SPA CORS支持或获得代理API启动并运行。
我发现您可以在Mac的Safari和Chrome中禁用CORS。
Chrome:退出Chrome,打开终端并粘贴以下命令: open /Applications/Google\ Chrome.app --args --disable-web-security --user-data-dir
Safari:在Safari中禁用同源策略
如果要在Safari上禁用同源策略(我有9.1.1),则只需启用开发人员菜单,然后从开发菜单中选择“禁用跨域限制”。
我已经解决了这个问题。
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。
花了整整一天半的时间来解决类似的问题后,我发现它与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特定代码
问题是应用程序池设置。
该托管管道模式设置为经典(把它改成集成)和标识设置为网络服务(将其改为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配置中。
我过去使用的一种解决方案-假设您的网站位于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网站上-然后您可以发出相同的原始请求,而无需任何选项请求:)
如果使用代理来拦截请求并写入适当的标头,则可以解决该问题。在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:https://developer.mozilla.org/fr/docs/Web/HTTP/Headers/Content-Security-Policy
CSP规范:https://www.w3.org/TR/CSP/