ajax 为什么经过身份验证的 CORS 请求的预检 OPTIONS 请求在 Chrome 中有效,但在 Firefox 中无效?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/15734031/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Why does the preflight OPTIONS request of an authenticated CORS request work in Chrome but not Firefox?
提问by maxbeatty
I am writing a JavaScript client to be included on 3rd party sites (think Facebook Like button). It needs to retrieve information from an API that requires basic HTTP authentication. The simplified setup looks like this:
我正在编写一个 JavaScript 客户端以包含在 3rd 方网站上(想想 Facebook Like 按钮)。它需要从需要基本 HTTP 身份验证的 API 中检索信息。简化的设置如下所示:
A 3rd party site includes this snippet on their page:
第 3 方网站在其页面上包含此代码段:
<script
async="true"
id="web-dev-widget"
data-public-key="pUbl1c_ap1k3y"
src="http://web.dev/widget.js">
</script>
widget.jscalls the API:
widget.js调用 API:
var el = document.getElementById('web-dev-widget'),
user = 'token',
pass = el.getAttribute('data-public-key'),
url = 'https://api.dev/',
httpRequest = new XMLHttpRequest(),
handler = function() {
if (httpRequest.readyState === 4) {
if (httpRequest.status === 200) {
console.log(httpRequest.responseText);
} else {
console.log('There was a problem with the request.', httpRequest);
}
}
};
httpRequest.open('GET', url, true, user, pass);
httpRequest.onreadystatechange = handler;
httpRequest.withCredentials = true;
httpRequest.send();
The API has been configured to respond with appropriate headers:
API 已配置为使用适当的标头进行响应:
Header set Access-Control-Allow-Credentials: true
Header set Access-Control-Allow-Methods: "GET, OPTIONS"
Header set Access-Control-Allow-Headers: "origin, authorization, accept"
SetEnvIf Origin "http(s)?://(.+?\.[a-z]{3})$" AccessControlAllowOrigin=// Base64 from http://www.webtoolkit.info/javascript-base64.html
auth = "Basic " + Base64.encode(user + ":" + pass);
...
// after open() and before send()
httpRequest.setRequestHeader('Authorization', auth);
Header set Access-Control-Allow-Origin %{AccessControlAllowOrigin}e env=AccessControlAllowOrigin
Note that the Access-Control-Allow-Originis set to the Origininstead of using a wildcard because I am sending a credentialed request (withCredentials).
请注意,Access-Control-Allow-Origin设置为Origin而不是使用通配符,因为我正在发送一个有凭据的请求 ( withCredentials)。
Everything is now in place to make an asynchronous cross-domain authenticated request, and it works great in Chrome 25 on OS X 10.8.2. In Dev Tools, I can see the network request for the OPTIONSrequest before the GETrequest, and the response comes back as expected.
现在一切就绪,可以发出异步跨域身份验证请求,并且在 OS X 10.8.2 上的 Chrome 25 中运行良好。在 Dev Tools 中,我可以在OPTIONS请求之前看到请求的网络GET请求,并且响应按预期返回。
When testing in Firefox 19, no network requests appear in Firebug to the API, and this error is logged in the console: NS_ERROR_DOM_BAD_URI: Access to restricted URI denied
在 Firefox 19 中测试时,Firebug 中没有出现对 API 的网络请求,并且在控制台中记录了此错误: NS_ERROR_DOM_BAD_URI: Access to restricted URI denied
After much digging, I found that Gecko doesn't allow the username and password to be directly in a cross-site URIaccording to the comments. I assumed this was from using the optional user and password params to open()so I tried the other method of making authenticated requests which is to Base64 encode the credentials and send in an Authorization header:
经过多方挖掘,根据评论,我发现Gecko不允许将用户名和密码直接放在跨站点URI中。我认为这是使用可选的用户和密码参数,open()所以我尝试了另一种发出经过身份验证的请求的方法,即对凭据进行 Base64 编码并在授权标头中发送:
<LimitExcept OPTIONS>
AuthType Basic
AuthName <AUTH_NAME>
Require valid-user
AuthUserFile <FILE_PATH>
</LimitExcept>
This results in a 401 Unauthorizedresponse to the OPTIONSrequest which lead to Google searches like, "Why does this work in Chrome and not Firefox!?" That's when I knew I was in trouble.
这会导致对导致 Google 搜索401 Unauthorized的OPTIONS请求的响应,例如“为什么这可以在 Chrome 而不是 Firefox 中工作!?” 那时我知道我遇到了麻烦。
Why doesit work in Chrome and not Firefox? How can I get the OPTIONSrequest to send and respond consistently?
为什么没有它在Chrome和Firefox的不是工作?如何获得OPTIONS一致发送和响应的请求?
回答by maxbeatty
Why doesit work in Chrome and not Firefox?
为什么没有它在Chrome和Firefox的不是工作?
The W3 spec for CORS preflight requestsclearly states that user credentials should be excluded. There is a bug in Chromeand WebKitwhere OPTIONSrequests returning a status of 401 still send the subsequent request.
CORS 预检请求的W3 规范明确指出应排除用户凭据。Chrome和WebKit中存在一个错误,即OPTIONS返回状态 401 的请求仍会发送后续请求。
Firefoxhas a related bug filed that ends with a link to the W3 public webapps mailing listasking for the CORS spec to be changed to allow authentication headers to be sent on the OPTIONSrequest at the benefit of IIS users. Basically, they are waiting for those servers to be obsoleted.
Firefox提交了一个相关的错误,该错误以指向W3 公共 Web 应用程序邮件列表的链接结尾,该链接要求更改 CORS 规范,以允许在OPTIONS请求时发送身份验证标头,以造福 IIS 用户。基本上,他们正在等待这些服务器被淘汰。
How can I get the OPTIONSrequest to send and respond consistently?
如何获得OPTIONS一致发送和响应的请求?
Simply have the server (API in this example) respond to OPTIONSrequests without requiring authentication.
只需让服务器(在本例中为 API)响应OPTIONS请求而不需要身份验证。
Kinveydid a good job expanding on this while also linking to an issue of the Twitter APIoutlining the catch-22 problem of this exact scenario interestingly a couple weeks before any of the browser issues were filed.
Kinvey在扩展这方面做得很好,同时还链接到Twitter API 的一个问题,有趣的是在任何浏览器问题被提交前几周概述了这个确切场景的 catch-22 问题。
回答by Sebastian Garavano
This is an old post but maybe this could help people to complete the CORS problem. To complete the basic authorization problem you should avoid authorization for OPTIONS requests in your server. This is an Apache configuration example. Just add something like this in your VirtualHost or Location.
这是一篇旧帖子,但也许这可以帮助人们完成 CORS 问题。要完成基本的授权问题,您应该避免对服务器中的 OPTIONS 请求进行授权。这是一个 Apache 配置示例。只需在您的 VirtualHost 或 Location 添加类似的内容。
##代码##回答by bitkorn
It was particular for me. I am sending a header named 'SESSIONHASH'. No problem for Chrome and Opera, but Firefox also wants this header in the list "Access-Control-Allow-Headers". Otherwise, Firefox will throw the CORS error.
这对我来说很特别。我正在发送一个名为“SESSIONHASH”的标头。Chrome 和 Opera 没问题,但 Firefox 也希望在“Access-Control-Allow-Headers”列表中包含此标题。否则,Firefox 会抛出 CORS 错误。

