由于浏览器设置的标头,Safari 拒绝重定向 CORS 请求
Posted
技术标签:
【中文标题】由于浏览器设置的标头,Safari 拒绝重定向 CORS 请求【英文标题】:Safari rejects redirected CORS request due to browser-set headers 【发布时间】:2017-01-14 05:31:29 【问题描述】:总结
Safari 拒绝一些涉及重定向的 CORS 请求,声称某些标头是不允许的。但是该标头从不被脚本请求,而是由浏览器添加,所以我认为应该没关系。
Safari 的行为是否存在错误, 规格是否有问题,或者 有这样的原因吗?错误表示 CORS 中不允许某些标头
我观察到 Safari 似乎比其他浏览器更严格地解释 CORS 协议的情况。它拒绝某些请求并显示错误消息
[错误] 加载资源失败:
Access-Control-Allow-Headers
不允许请求标头字段。
我在标题字段Accept-Encoding
中看到了这一点,在将该字段添加到Access-Control-Allow-Headers
之后,DNT
重复了相同的错误。预检请求的Access-Control-Request-Headers
列表中包含的其他字段为Cache-Control
、Origin
和Accept-Language
。
据我所知,这只会影响被重定向的请求。在我设法立即命名最终位置的情况下,请求成功。
WHATWG XHR:请求不应有作者设置的标头
我在自己的代码中创建了XMLHttpRequest
,没有任何库或框架干扰它。我绝对确定我从未调用过setRequestHeader()
方法。
按照WHATWG XHR spec,因此我假设我的author request headers 列表应该是空的。 Request 部分指出:
author request headers 最初是空的 header list。
我可以在文档中读到 send()
的非空参数可能会触发 Content-Type
作为作者请求标头,但即使是这样的无参数调用我也遇到了问题。
W3C CORS:只有作者设置的标头才重要
W3C CORS recommendation 将the Access-Control-Request-Headers
field 描述为由作者请求标头组成:
如果author request headers 不为空,则包含一个
Access-Control-Request-Headers
标头,其标头字段值为author request headers 中按字典顺序排列的标头字段名称的逗号分隔列表,每个converted to ASCII lowercase(即使有一个或多个simple header)。
根据该规范,我看到的错误的可能原因是:
如果author request headers 中每个标头的字段名称不是ASCII case-insensitive 匹配headers 中的标头字段名称之一,并且标头不是simple header,则应用@ 987654337@.
WHATWG Fetch 从 XHR 获取列表
也许 W3C CORS 建议是错误的地方。也许它已被WHATWG Fetch living standard 取代?在其部分中写到CORS-preflight fetch
让 headers 成为 request 的 header list 的 headers 的 names,不包括 CORS-safelisted request-headers 和重复项,按字典顺序排序,和byte-lowercased。
设 value 为 headers 中的项目,彼此之间用 0x2C 隔开。
Set
Access-Control-Request-Headers
到 preflight 的 header list 中的 value。
那么这里的标题列表是什么? XHR 和 Fetch 的生活水平之间的联系似乎是 the send()
method specification。
令req为一个新的request,初始化如下:
method: request method url: request URL header list: author request headers unsafe-request flag: 设置。 […]
因此它将作者请求标头(根据我上面的考虑应该为空)绑定到用于构建请求标头列表的标头列表。至少在最初。
可能会添加标题
当然,Fetch 规范很长,并且在很多处提到了“标题列表”一词。很可能那里有一些条款要求添加某些标题字段。但我看不到任何部分明确提及Accept-Encoding
或DNT
作为预期添加。它们被列为forbidden headers,作者不应对其进行控制。
但是,HTTP-network-or-cache fetch 部分的以下文本在注释中提到了它们:
根据 HTTP 修改 httpRequest 的 header list。
注意:如果我们能以某种方式使其更加规范,那就太好了。此时headers如
Accept-Encoding
、Connection
、DNT
和Host
,如有必要,应为appended。此时不得包含
Accept
、Accept-Charset
和Accept-Language
。注意:
Accept
和Accept-Language
已经包含了(除非使用fetch()
,默认不包含后者),Accept-Charset
是浪费字节。有关详细信息,请参阅HTTP header layer division。
我发现很难判断此添加的范围。除了作者指定的那些之外,这是否是“为每个 HTTP 添加标头”导致为 CORS 考虑额外标头的原因?但为什么只在重定向的情况下? HTTP-redirect fetch 部分没有提到向请求标头列表中添加更多标头。
观察到的行为会很糟糕
如果我观察到的行为符合规范,那么我主要担心的是它基本上会阻止添加新的有用的 HTTP 标头。您永远不会知道哪些网站可能会突然被破坏,因为浏览器不仅开始添加它们,而且还将它们包含在 CORS 检查中。另一方面,只考虑作者创建的脚本,将请求创建库与服务器实现相匹配就足够了,而不必担心浏览器会做什么。对我来说,这听起来像是一个更理智的设置。
问题
所以我重复我的主要问题:
Safari 的行为是否存在错误, 规格是否有问题,或者 有这样的原因吗?解决方法
对于一台服务器,我刚刚通过configuring my Apache 到return all headers 解决了这个问题,但这更像是一种解决方法。我想真正了解 Safari 在这里做什么,以及为什么。
交叉链接
SO上有几个问题表明Safari在CORS和重定向的结合上存在问题:
Safari Ajax cors request not following redirect (2013) 接受的答案指出“Apple 声称这是编写 html 规范的方式”,但没有引用来源。听起来像Webkit bug 112471 comment 2,只是答案早于评论。
HTML5 CORS request fails in safari after redirect (2014) 接受的自我回答提出了一种服务器辅助的解决方法。
Safari fails CORS request after 302 redirect (2015)
未接受的答案提到 webkit bug 98838(未确认),这反过来又建议 bug 112471(最近修复)。那个人在某些时候还提到了bug 63460,标题为“CORS 应该只处理脚本作者设置的请求标头”,但似乎并没有就此达成明确的共识。接近尾声时,DNT
标志被明确命名。
Safari turns Simple Cors Request into Preflight after 302 redirect (2015) 无人接听。
右侧的类似问题列表可能会提供更多信息。
【问题讨论】:
【参考方案1】:如果你下次分开提问可能会有所帮助。
WHATWG Fetch 确实淘汰了 CORS(它内联定义了 CORS)。 CORS 只关注网络级别之前设置的标头(基本上只关注那些在 API 级别设置的标头)。其中一些可以由浏览器设置,例如,Accept
,但我想不出会影响 CORS 的。
是的,我认为 Safari 有一个错误,但他们最近一直在这方面做出改变,所以 WebKit nightlies 或 Safari Technology Preview 可能会做得更好。
【讨论】:
以上是关于由于浏览器设置的标头,Safari 拒绝重定向 CORS 请求的主要内容,如果未能解决你的问题,请参考以下文章
是否最好使用HTTP标头重定向到不同的页面/文档,或者合并动态消息以通知用户拒绝访问?