CORS:为什么我的浏览器没有发送OPTIONS预检请求?

时间:2016-08-03 11:32:49

标签: javascript jquery cors

根据我对CORS的了解,我了解它应该如下工作:

  1. 客户端上的脚本尝试从来源不同的服务器获取资源
  2. 浏览器拦截此请求,首先将预检OPTIONS请求发送到同一网址。
  3. 如果此预检请求的响应包含相应的标题(例如Access-Control-Allow-Origin: *),则浏览器会理解其允许发送主要请求并执行此操作
  4. 响应将返回给客户端脚本。
  5. 我为此设置了一个测试:

    • 服务器在Go中接受两者 - GET和OPTIONS请求(使用CURL检查) - 并设置Access-Control-*标头作为响应
    • 简单的HTML页面(由另一个端口上的另一个服务器提供),其中包含以下脚本($代表jQuery):

      $.ajax({
        type: "GET",
        crossDomain: true,
        url: "http://local.site.com/endpoint,
        success: function (data) {
          alert(data);
        },
        error: function (request, error) {
          alert(error);
        }
      });
      

    但是,当我调用此方法时,我在“网络”标签中只看到一个GET且没有预检OPTIONS请求 - Chrome 49和Firefox 33.

    以下是Chrome的GET请求详情:

    Accept:*/*
    Accept-Encoding:gzip, deflate, sdch
    Accept-Language:en-US,en;q=0.8,ru;q=0.6
    Connection:keep-alive
    Host:local.adform.com
    Origin:http://localhost:7500
    Referer:http://localhost:7500/test-page.html
    User-Agent:Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.87 Safari/537.36
    

    和相应的回应:

    Access-Control-Allow-Headers:Accept, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization
    Access-Control-Allow-Methods:POST, GET, OPTIONS, PUT, DELETE
    Access-Control-Allow-Origin:*
    Content-Length:2
    Content-Type:text/plain; charset=utf-8
    Date:Wed, 03 Aug 2016 10:53:19 GMT
    

    为什么我的浏览器没有发送预检请求的任何想法?

1 个答案:

答案 0 :(得分:9)

正如评论员指出的那样,使用GET 浏览器并不总是发送预检OPTIONS请求。如果确实需要预检,那么让浏览器发送它的一种方法是设置自定义标题(例如" X-PINGOVER:乒乓球"或其他)。请注意,该服务器还应该允许此请求标头,方法是将其添加到" Access-Control-Allow-Headers" 响应标题

我的基本目标是将 Cookie 与域a.com一起传递到a.com的服务器,但是从另一个网站b.com的页面传递(常见)用例就是在第三方网站上跟踪您的用户)。事实证明,与请求一起发送cookie会涉及更多的工作。

客户端(即在JavaScript中),需要启用跨域请求并允许传递凭据。例如。 jQuery的以下请求对我有用:

$.ajax({
  type: "GET",
  url: "http://example.com",
  xhrFields: {
    withCredentials: true           // allow passing cookies
  },
  crossDomain: true,                // force corss-domain request                
  success: function (data) { ... },
  error: function (request, error) { ... }
});

服务器端,需要设置2个响应头:

  • Access-Control-Allow-Credentials: true
  • Access-Control-Allow-Origin: <requester origin>

其中<requester origin>是执行呼叫的网站的协议+主机+端口。请注意,泛型*在许多浏览器中可能不起作用,因此服务器解析请求的标头Referer并使用特定的允许来源进行响应是有意义的。