【问题标题】:CORS pre-flight comes back with Access-Control-Allow-Origin:*, browser still fails requestCORS 飞行前返回 Access-Control-Allow-Origin:*,浏览器仍然失败请求
【发布时间】:2013-08-02 22:33:13
【问题描述】:

触发 AJAX GEThttp://qualifiedlocalhost:8888/resource.json 会启动预期的 CORS 预飞行,看起来它会正确返回:

飞行前OPTIONS请求

Request URL:http://qualifiedlocalhost:8888/resource.json
Request Method:OPTIONS
Status Code:200 OK

请求标头

Accept:*/*
Accept-Encoding:gzip,deflate,sdch
Accept-Language:en-US,en;q=0.8
Access-Control-Request-Headers:accept, origin, x-requested-with
Access-Control-Request-Method:GET
Cache-Control:no-cache
Connection:keep-alive
Host:qualifiedlocalhost:8888
Origin:http://localhost:9000
Pragma:no-cache
Referer:http://localhost:9000/
User-Agent:Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.71 Safari/537.36

响应标头

Access-Control-Allow-Headers:Content-Type, X-Requested-With
Access-Control-Allow-Methods:GET,PUT,POST,DELETE
Access-Control-Allow-Origin:*
Connection:keep-alive
Content-Length:2
Content-Type:text/plain
Date:Thu, 01 Aug 2013 19:57:43 GMT
Set-Cookie:connect.sid=s%3AEpPytDm3Dk3H9V4J9y6_y-Nq.Rs572s475TpGhCP%2FK%2B2maKV6zYD%2FUg425zPDKHwoQ6s; Path=/; HttpOnly
X-Powered-By:Express

看起来不错?

所以它应该有效,对吧?

但是后面的请求还是失败了,报错XMLHttpRequest cannot load http://qualifiedlocalhost:8888/resource.json. Origin http://localhost:9000 is not allowed by Access-Control-Allow-Origin.

真实请求

Request URL:http://qualifiedlocalhost:8888/resource.json

请求标头

Accept:application/json, text/plain, */*
Cache-Control:no-cache
Origin:http://localhost:9000
Pragma:no-cache
Referer:http://localhost:9000/
User-Agent:Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.71 Safari/537.36
X-Requested-With:XMLHttpRequest

救命!

也许它就在我面前凝视着。但是,有什么想法吗?以防万一它是相关的......我正在使用 AngularJS $resource 并与 CompoundJS 服务器交谈。

【问题讨论】:

  • 谢谢。我的网址已转义冒号。这些请求/响应快照来自 Chrome 开发工具,因此它们处于浏览器级别。
  • 您省略了实际 GET 请求的响应标头。那些看起来像什么?
  • Chrome 阻止了请求的发送,所以根本没有响应。
  • 如果 Chrome 阻止发送请求,那么您的预检没有成功。因此,您似乎在这里遗漏了一些重要信息。此外,您的预检和实际 GET 请求似乎不匹配(不同的请求域和资源)。

标签: javascript node.js express cors jqxhr


【解决方案1】:

将您的 Access-Control-Allow-Methods: 'GET, POST' 更改为 'GET, POST, PUT, DELETE'

之前:

   app.use(function(req, res, next) {
        res.setHeader('Access-Control-Allow-Origin', '*');
        res.setHeader('Access-Control-Allow-Methods', 'GET, POST');
        res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type, Authorization');
        next();
    });

之后:

app.use(function(req, res, next) {
    res.setHeader('Access-Control-Allow-Origin', '*');
    res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT ,DELETE');
    res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type, Authorization');
    next();
});

【讨论】:

    【解决方案2】:

    recently had the same issue。问题是Access-Control-Allow-Origin 标头(以及,如果您使用它,Access-Control-Allow-Credentials 标头)必须在 预检响应和实际响应中发送。

    您的示例仅在预检响应中包含它。

    【讨论】:

      【解决方案3】:

      您的 Web 服务器/获取功能是否还包括 HTTP 标头:Access-Control-Allow-Origin?我最终使用 AngularJS 1.0.7 和一个远程 Java servlet 成功地添加了这个功能。这是我的 Java 代码 sn-p——AngularJS 客户端不需要更改:

      小服务程序:

      @Override
      protected void doOptions(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
          // Send Response
          super.doOptions(request,  response);
          response.setHeader("Access-Control-Allow-Origin", "*");
          response.setHeader("Access-Control-Allow-Headers", "Content-Type, X-Requested-With");
      }
      
      @Override
      protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
          /* ... */
          response.setHeader("Access-Control-Allow-Origin", "*");
      }
      

      更优雅的替代方案是 servlet 过滤器。

      【讨论】:

      • 是的,在上述所有场景中,服务器正在发送正确的 CORS 标头。
      • 这是唯一适合我的方法。 resp.setHeader("Access-Control-Allow-Origin", "*");
      【解决方案4】:

      我们注意到了同样的问题,服务器发送了正确的 CORS 标头,但浏览器失败了,因为它认为 CORS 要求没有得到满足。更有趣的是,在我们的例子中,它只发生在同一浏览器会话中的一些 AJAX 调用上,但不是全部。

      工作原理...

      清除浏览器缓存解决了我们案例中的问题——我目前的工作理论是这与跨源服务器设置的 cookie 有关。我注意到在您的场景中,设置了一个 cookie 作为对飞行前 OPTIONS 请求的响应的一部分。您是否尝试过让该服务器不为来自不同来源的请求设置任何 cookie?

      但是,我们注意到在某些情况下,重置浏览器后问题再次出现。此外,在私有模式下运行浏览器会导致问题消失,这表明存在与浏览器缓存中的内容有关的问题。

      作为参考,这是我的场景(我几乎把它作为一个新问题发布在 SO 中,但把它放在这里):

      我们遇到了一个错误,其中 一些 通过 jQuery.ajax 发出的 CORS GET 请求失败。在给定的浏览器会话中,我们看到飞行前的 OPTIONS 请求通过,然后是实际请求。在同一个会话中,一些请求通过而其他请求失败。

      浏览器网络控制台中的请求和响应顺序如下所示:

      首先是 OPTIONS 飞行前请求

      OPTIONS /api/v1/users/337/statuses
      HTTP/1.1 Host: api.obfuscatedserver.com 
      Connection: keep-alive 
      Access-Control-Request-Method: GET 
      Origin: http://10.10.8.84:3003 
      User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.95 Safari/537.36
      Access-Control-Request-Headers: accept, origin, x-csrf-token, auth 
      Accept: */* Referer: http://10.10.8.84:3003/ 
      Accept-Encoding: gzip,deflate,sdch Accept-Language: en-US,en;q=0.8
      

      得到这样的回应,

      HTTP/1.1 200 OK 
      Date: Tue, 06 Aug 2013 19:18:22 GMT 
      Server: Apache/2.2.22 (Ubuntu) 
      Access-Control-Allow-Origin: http://10.10.8.84:3003 
      Access-Control-Allow-Methods: GET, POST, OPTIONS, PUT 
      Access-Control-Max-Age: 1728000 
      Access-Control-Allow-Credentials: true 
      Access-Control-Allow-Headers: accept, origin, x-csrf-token, auth 
      X-UA-Compatible: IE=Edge,chrome=1 
      Cache-Control: no-cache 
      X-Request-Id: 4429c4ea9ce12b6dcf364ac7f159c13c 
      X-Runtime: 0.001344 
      X-Rack-Cache: invalidate, pass 
      X-Powered-By: Phusion 
      Passenger 4.0.2 
      Status: 200 OK 
      Vary: Accept-Encoding
      Content-Encoding: gzip
      

      然后是实际的GET请求,

      GET https://api.obfuscatedserver.com/api/v1/users/337
      HTTP/1.1 
      Accept: application/json, text/javascript, */*; q=0.01 
      Referer: http://10.10.8.84:3003/ 
      Origin: http://10.10.8.84:3003 
      X-CSRF-Token: xxxxxxx 
      User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.95 Safari/537.36 
      auth: xxxxxxxxx
      

      在浏览器控制台中出现错误,例如,

      XMLHttpRequest
        cannot load https://api.obfuscatedserver.com/api/v1/users/337.
        Origin http://10.10.8.84:3003 is not allowed by Access-Control-Allow-Origin.
      

      其他调试

      我可以通过 curl 重播相同的序列,并且我看到来自服务器的有效响应。即它们具有应该让请求通过的预期 CORS 标头。

      在私人/隐身浏览器窗口中运行相同的场景并没有重现问题。这导致我尝试清除缓存,这也使问题消失了。但过了一会儿,它又回来了。

      问题是在 iPhone safari 以及 OSX 桌面上的 Chrome 上重现。

      我真正需要帮助的地方

      我怀疑在跨域域中设置了一些 cookie,这些 cookie 在这里涉及并可能暴露浏览器中的错误。我可以在浏览器(本机堆栈?)中设置工具或断点来尝试进一步调试吗?评估 CORS 策略的代码中的断点是理想的。

      【讨论】:

      • 有没有人有关于如何闯入 chrome 并在 CORS 请求失败时查看它在做什么的提示?
      • 有人知道这方面的更多信息吗?我遇到了同样的问题,无法解决。
      • @jdscolam 我们永远无法让它工作,所以最终在源服务器上实现了一个代理,以将适当的请求转发到 x 域服务器。在我们的例子中,这些都是转到我们 API 端点的 XHR 调用,很容易根据传入的 URL 路径映射它们。
      • 如果您的浏览器请求一个没有 CORS 或具有不同来源的资源,然后又请求相同的资源,则该资源的缓存副本具有原始请求的访问控制允许来源。如果多个子域从同一个子域请求资源,就会发生这种情况。来源不同,都是允许的,但是缓存的资源只对第一个请求它的人有效。
      • Access-Control-Max-Age: 1728000 会导致该资源的 CORS 配置被缓存很长时间。缓存的不是 cookie,而是 CORS 规则本身。所以例如如果您在开发期间更改了 CORS 要求,但没有刷新规则,那么它可能会失败。清除浏览器缓存然后“修复”它。一旦一切正常并解决,缓存有助于减少生产中预检 OPTIONS 请求的数量,但在开发时,您不希望缓存时间如此之长。
      【解决方案5】:

      看起来您对“选项”的回复工作正常。问题似乎出在“获取”响应中。

      您需要让“get”响应返回与“options”响应相同的 CORS 标头。

      特别是,“获取”响应应包括

      Access-Control-Allow-Headers:Content-Type, X-Requested-With
      Access-Control-Allow-Methods:GET,PUT,POST,DELETE
      Access-Control-Allow-Origin:*
      

      【讨论】:

      • 只有Access-Control-Allow-Origin (如果你使用它,Access-Control-Allow-Credentials是必需的
      猜你喜欢
      • 2021-12-05
      • 2019-08-02
      • 1970-01-01
      • 2014-11-20
      • 2021-05-12
      • 2018-03-05
      • 2013-12-09
      • 2014-09-03
      • 2014-08-16
      相关资源
      最近更新 更多