我正在编写一个JavaScript客户端,该客户端将包含在第3方网站上(想像Facebook Like按钮)。它需要从需要基本HTTP身份验证的API检索信息。简化的设置如下所示:
第三方网站的网页上包含以下代码段:
<script async="true" id="web-dev-widget" data-public-key="pUbl1c_ap1k3y" src="http://web.dev/widget.js"> </script>
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();
已将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=$0 Header set Access-Control-Allow-Origin %{AccessControlAllowOrigin}e env=AccessControlAllowOrigin
请注意,将Access-Control-Allow- Origin设置为,Origin而不是使用通配符,因为我正在发送凭据请求(withCredentials)。
Access-Control-Allow- Origin
Origin
withCredentials
现在一切就绪,可以进行异步的跨域身份验证请求,并且在OS X 10.8.2的Chrome 25中运行良好。在开发工具中,我可以在OPTIONS请求之前看到请求的网络GET请求,并且响应将按预期返回。
OPTIONS
GET
在Firefox 19中进行测试时,Firebug中没有向API发出网络请求,并且此错误记录在控制台中: NS_ERROR_DOM_BAD_URI: Access to restricted URI denied
NS_ERROR_DOM_BAD_URI: Access to restricted URI denied
经过大量挖掘,我发现Gecko不允许用户名和密码根据评论直接在跨站点URI中。我以为这是从使用可选的用户和密码参数开始的,open()所以我尝试了另一种进行身份验证的请求的方法,即对Base64编码凭据并发送Authorization标头:
open()
// Base64 from http://www.webtoolkit.info/javascript-base64.html auth = "Basic " + Base64.encode(user + ":" + pass); ... // after open() and before send() httpRequest.setRequestHeader('Authorization', auth);
结果是401 Unauthorized对OPTIONS请求的响应导致了Google搜索,例如“为什么这在Chrome而不是Firefox中有效!”。那是我知道自己遇到麻烦的时候。
401 Unauthorized
为什么 没有 它在Chrome和Firefox的不是工作?如何获得OPTIONS一致发送和响应的请求?
为什么 没有 它在Chrome和Firefox的不是工作?
针对CORS预检请求的[W3规范明确指出应排除用户凭据。Chrome和WebKit中存在一个错误,其中OPTIONS返回状态401的请求仍会发送后续请求。
Firefox有一个相关的错误文件,该错误的结尾是一个指向W3公共Web应用程序邮件列表的链接,该链接要求更改CORS规范,以允许OPTIONS对IIS用户有利的请求发送身份验证标头。基本上,他们正在等待这些服务器被淘汰。
如何获得OPTIONS一致发送和响应的请求?
只需让服务器(在此示例中为API)响应OPTIONS请求即可,而无需身份验证。
Kinvey在扩展此功能方面做得很好,同时还与TwitterAPI的问题进行了链接,概述了这种确切情况的catch22问题,有趣的是,在提出任何浏览器问题之前几周。