首页 文章

为什么发送OPTIONS请求并且可以禁用它?

提问于
浏览
252

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

15 回答

  • -2

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

    我的Web API项目设置如下:

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

    web.config> system.webServer节点中的 I did not have CORS specific config options 就像我在很多帖子中看到过的那样

    No CORS specific code in the global.asax or in the controller as a decorator

    问题是 app pool settings .

    managed pipeline mode 设置为classic(将其更改为集成), Identity 设置为Network Service(将其更改为ApplicationPoolIdentity)

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

  • 125

    edit 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

    CORS Flowchart


    edit 2018-09-13

    CORS OPTIONS 请求仅在某些情况下触发,如MDN docs中所述:

    某些请求不会触发CORS预检 . 这些在本文中称为“简单请求”,尽管Fetch规范(定义CORS)不使用该术语 . 不触发CORS预检的请求 - 即所谓的“简单请求” - 满足以下所有条件的请求:唯一允许的方法是:GET HEAD POST除了用户代理自动设置的标头(用于例如,Connection,User-Agent或任何其他 Headers ,其名称在Fetch规范中定义为“禁止 Headers 名称”),允许手动设置的唯一 Headers 是Fetch规范定义为a的 Headers “CORS-safelisted request-header”,它们是:接受Accept-Language Content-Language Content-Type(但请注意下面的附加要求)DPR Downlink Save-Data Viewport-Width Width Content-Type标头的唯一允许值是:application / x-www-form-urlencoded multipart / form-data text / plain在请求中使用的任何XMLHttpRequestUpload对象上都没有注册事件侦听器;这些是使用XMLHttpRequest.upload属性访问的 . 请求中不使用ReadableStream对象 .

  • 12

    请参考此答案,了解预先发出的OPTIONS请求的实际需求:CORS - What is the motivation behind introducing preflight requests?

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

    • 请求未设置自定义HTTP标头,如'application/xml'或'application/json'等

    • 请求方法必须是GET,HEAD或POST之一 . 如果是POST,则内容类型应为 application/x-www-form-urlencodedmultipart/form-datatext/plain 之一

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

  • -1

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

    根据CORS strategy(强烈建议你阅读它)你不能强迫浏览器停止发送OPTION请求,如果认为它需要 .

    有两种方法可以解决它

    • 确保您的请求是"simple request"

    • 为OPTION请求设置 Access-Control-Max-Age

    简单请求

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

    唯一允许的方法是: - GET - HEAD - POST

    除了由用户代理自动设置的 Headers (例如,连接,用户代理等)之外,允许手动设置的唯一 Headers 是: - 接受 - 接受 - 语言 - 内容 - 语言 - 内容类型

    Content-Type标头唯一允许的值是: - application / x-www-form-urlencoded - multipart / form-data - text / plain

    简单的请求不会导致飞行前的OPTION请求 .

    为OPTION检查设置缓存

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

    Access-Control-Max-Age以秒为单位显示可以缓存对预检请求的响应的时间长度,而不发送另一个预检请求 .

  • 0

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

    看看这里:https://github.com/jpillora/xdomain

    工作示例:http://jpillora.com/xdomain/

    祝你今天愉快!

  • -1

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

  • 6

    如前几篇文章中所述, OPTIONS 请求是有原因的 . 如果您的服务器响应时间很长(例如海外连接),您也可以让浏览器缓存预检请求 .

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

  • 37

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

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

    Disable same origin policy in Chrome

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

    Safari:Disabling same-origin policy in Safari

    如果要在Safari上禁用同源策略(我有9.1.1),则只需启用开发人员菜单,然后从开发菜单中选择“禁用跨源限制” .

  • 14

    我已经解决了这个问题 .

    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 但开发是我的本地 .

  • -2

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

  • -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就会始终添加Content-Type标头,这不在我以前的AllowedHeaders配置中 .

  • 5

    我想,您正在向 cross domain 发送请求 .

    对于跨域请求,将内容类型设置为application / x-www-form-urlencoded,multipart / form-data或text / plain以外的任何内容将触发浏览器向服务器发送预检OPTIONS请求 .

    因此,您可能需要指定 contentType 以避免OPTION请求 .

    Jquery示例: -

    $.ajax({
        url: "http://crossdomainurl",
        type: "POST",
        contentType: 'text/plain'
    });
    
  • 229

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

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

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

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

  • 40

    我过去使用的一个解决方案 - 假设您的网站位于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网站上 - 然后你可以发出相同的原始请求,并且不需要任何选项请求:)

  • 118

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

    }

相关问题