CORS 预检在 Firefox 中失败,但在 Chrome for Apache CXF 中有效

Posted

技术标签:

【中文标题】CORS 预检在 Firefox 中失败,但在 Chrome for Apache CXF 中有效【英文标题】:CORS preflight fails in Firefox but works in Chrome for Apache CXF 【发布时间】:2017-01-22 14:30:41 【问题描述】:

我正在向 Java Web 应用程序添加对 CORS 请求的支持,但由于某种未知原因,Firefox 未正确发送(或接收)Content-Type 标头。该应用程序在 Jetty Web 服务器上运行,但在 Chrome 中一切正常。

我不确定问题出在 Firefox、Jetty 还是我们的前端应用程序中,但发生了一些奇怪的事情

根据 Firefox 的请求和响应标头:

请求

Host: localhost:8889
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:50.0) Gecko/20100101 Firefox/50.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Access-Control-Request-Method: POST
Access-Control-Request-Headers: authorization,content-type
Origin: http://localhost:7778
DNT: 1
Connection: keep-alive

回应

Access-Control-Allow-Origin: http://localhost:7778
Content-Length: 0
Date: Wed, 14 Sep 2016 17:10:36 GMT, Wed, 14 Sep 2016 17:10:36 GMT
Server: Jetty(8.1.14.v20131031)
access-control-allow-credentials: true
access-control-allow-headers: authorization, -type
access-control-allow-methods: POST

在 Chrome 中提出同样的请求:

请求

OPTIONS *redacted* HTTP/1.1
Host: localhost:8889
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache
Access-Control-Request-Method: POST
Origin: http://localhost:7778
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36
Access-Control-Request-Headers: authorization, content-type
Accept: */*
DNT: 1
Referer: http://localhost:7778/
Accept-Encoding: gzip, deflate, sdch
Accept-Language: en-US,en;q=0.8

回应

HTTP/1.1 200 OK
Date: Wed, 14 Sep 2016 16:14:34 GMT
Access-Control-Allow-Credentials: true
Access-Control-Allow-Headers: authorization, content-type
Access-Control-Allow-Methods: POST
Access-Control-Allow-Origin: http://localhost:7778
Content-Length: 0
Date: Wed, 14 Sep 2016 16:14:34 GMT
Server: Jetty(8.1.14.v20131031)

发出请求的代码是一个普通的 jQuery 调用;

$.ajax(
    "url": "http://localhost:8889/...",
    "method": "POST",
    "accepts": "*/*",
    "headers": 
        "Authorization": "Basic ..." // yes, I know. it's a legacy app
    ,
    "xhrFields": 
        "withCredentials": true
    ,
    "contentType": "application/json",
    "data": "..."
)

我尝试搜索 Jetty 和 Firefox 之间的奇怪交互,在 Mozilla 的错误跟踪器中进行了挖掘(运气不佳),并禁用了两个浏览器中的所有扩展以消除任何奇怪的插件问题。到目前为止,我所做的一切都没有改变。我在这里束手无策。我错过了什么?

【问题讨论】:

Jetty 8 is EOL (End of Life) 考虑升级。 不幸的是,目前这不是一个选项。我喜欢能够升级,尽管它目前超出了我们现有功能的范围。但是,如果问题在于 Jetty 8 的 CORS 支持有问题,它可能会给我一些推动我们升级的筹码。 响应中的access-control-allow-headers: authorization, -type 是服务器实际返回的字面意思吗?只是-type 而不是content-type @sideshowbarker 目前还不清楚。我的倾向是说服务器正确地发回content-type,因为 Chrome 在服务器响应中收到了正确的标头。但我无法想象 Firefox 如何/为什么会以这种特定(且一致)的方式破坏标题。 【参考方案1】:

tl;dr

Apache CXF 在其 CORS 过滤器类中有一个错误。该错误仅存在于真正的旧版本中。将 CXF 更新到 2.7.6 或更高版本可以解决此问题。


最近,当我们遇到更多与之相关的客户问题时,我又回到了这个错误。我终于找到了来源,并认为我会把它贴在这里,以防其他人遇到同样的情况。不过,鉴于修复的性质,我希望大多数人都安全。

原因归结为 Apache CXF 库中的 CrossOriginResourceSharingFilter 类。我们使用的版本(一个版本)在其标头解析中存在错误,该错误已在以后的版本中进行了修补。

具体来说,过滤器使用,\w* 作为标头值的分隔符,我认为它应该是,\s*。因此,逗号分隔的列表在逗号后面也没有空格,会被错误地解析。

由于这个错误很久以前就被修复了,我希望很少有人需要这个答案。但我知道公司在更新第三方库(如我们的例子)时可能会行动缓慢,所以我想把它放在那里。

【讨论】:

根据答案,您可以考虑将cxf 添加到问题标签中(这意味着删除当前标签之一,但似乎CXF 最相关)。 @sideshowbarker 好电话。我编辑了原始标签以将 Jetty 换成 CXF。【参考方案2】:

对我来说,问题是在同一端口上的本地主机上运行两台服务器。我不知道一台服务器正在运行,但它是发送错误 CORS 响应的服务器。我不知道为什么它似乎总是在 Chrome 上运行。

【讨论】:

以上是关于CORS 预检在 Firefox 中失败,但在 Chrome for Apache CXF 中有效的主要内容,如果未能解决你的问题,请参考以下文章

CORS withCredentials XHR 预检未在 Firefox 中发布 Cookie

Ionic - $http 在移动设备中工作,但在浏览器中显示 CORS 和预检错误

在启动中启用 CORS 失败并出现预检错误

将 Spring Security(双向 SSL)配置为仅对 CORS 预检 OPTIONS 请求进行身份验证

CORS 适用于 chrome 但不适用于 firefox、angularjs

IE 11 上 CORS 预检请求的奇怪问题失败