这里发生了很多不同的事情,所以我一次回答一个。
Chrome 和 Safari 都基于 WebKit,这就是为什么您会在这些浏览器中看到相同的行为(Chrome 即将迁移到 Blink,但尚未掌握在用户手中)。
最新的 CORS 规范指出这Accept
是一个简单的请求标头。Origin
不包含在简单请求标头列表中,但是不支持它会很愚蠢,因为它是 CORS 的基础。所以从技术上讲,Firefox 正在做正确的事情。
但是请注意,尽管 Chrome/Safari 包含Accept
和Origin
标头,但它们不会验证这些标头是否包含在Access-Control-Allow-Headers
响应标头中。您可以通过访问以下链接来验证这一点:
http://client.cors-api.appspot.com/client#?client_method=PUT&client_credentials=false&client_headers=Accept%3A%20%2A%2F%2A&server_enable=true&server_status=200&server_credentials=false&server_methods=PUT&server_tabs=local
请注意,预检请求有 header Access-Control-Request-Headers: accept, origin
,但Access-Control-Allow-Headers
响应中没有。并且实际的 CORS 请求仍然成功。
Content-Type
仅当其值为以下之一时,该标头才被视为简单请求标头:application/x-www-form-urlencoded
、multipart/form-data
或text/plain
。所有其他值将触发预检。这可能就是您在这里看到的。
我不知道为什么浏览器会这样。这可能是值得在 WebKit 或 Firefox 留言板上询问的内容。下面是 WebKit 设置Access-Control-Request-Headers
标头的代码:
https://trac.webkit.org/browser/trunk/Source/WebCore/loader/CrossOriginAccessControl.cpp?order=name#L117
它似乎列出了所有标题,而没有删除简单的标题。我想响应端的代码只需要响应中的非简单标头Access-Control-Allow-Headers
。