考虑以下跨域请求(在Safari 5.0.2中可复制的f.ex.,任何操作系统):
请求
var xhr = new XMLHttpRequest();
xhr.open('GET', 'http://myhost.tld/odata/Account(518059)', false);
xhr.setRequestHeader('Authorization','Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdWQiOiJsb2phYWxpLXdlYmFwaS5jbG91ZGFwcC5uZXQiLCJleHAiOjEzOTQxMjM2MzcsImlzcyI6IldlYkFwaSIsImNhbXBJZCI6MjksInBvcnRhbElkIjozMiwidXNlcklkIjo1MTgwNTl9.c8223aYpb4X7kwYLSmSSQr4wGytxcYtOzTlQuHa9mYU');
xhr.send();
xhr.responseText;
响应
Error: NETWORK_ERR: XMLHttpRequest Exception 101
接头
OPTIONS /odata/Account(518059) HTTP/1.1
Host: myhost.tld
Accept: */*
Accept-Language: en-US
Access-Control-Request-Method: GET
Origin: http://myclient.tld
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.2; en-US) AppleWebKit/533.18.1 (KHTML, like Gecko) Version/5.0.2 Safari/533.18.5
Accept-Encoding: gzip, deflate
Access-Control-Request-Headers: Authorization
Content-Length: 0
Connection: keep-alive
Connection: keep-alive
HTTP/1.1 200 OK
Cache-Control: no-cache
Pragma: no-cache
Expires: -1
Server: Microsoft-IIS/8.5
Access-Control-Allow-Origin: http://myclient.tld
Access-Control-Allow-Methods: GET
Access-Control-Allow-Headers: Authorization
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
Date: Thu, 06 Mar 2014 16:37:26 GMT
Content-Length: 0
我验证了web api正确处理了请求并确实使用HTTP 200返回数据。但是,某些旧版浏览器上的请求似乎失败了。因此,我继续对服务器端的授权令牌进行硬编码,并将其从等式中删除:
请求
var xhr = new XMLHttpRequest();
xhr.open('GET', 'http://myhost.tld/odata/Account(518059)', false);
xhr.send();
xhr.responseText;
响应
{
'odata.metadata': 'http://myhost.tld/odata/$metadata#Account/@Element',
'Id': 518059,
'userName': '643033849'
}
Voilà,它突然开始工作了。所以,我将整个互联网下载到我的硬盘并阅读它,但无法找到f.ex.的验证。较旧的Safaris不支持带有跨域请求的自定义标头,我也无法在不进入明显的Http Handler或JSONP路由的情况下找到可能的情况。
因此,除了前面提到的“修复”之外,我还能做些什么来安全地将此令牌从我的客户端传输到服务器,从而避免使用自定义标头。或者,有没有办法让它们起作用?
缓存吗
请不要建议这个。除非用户访问了跨域请求的目标站点,否则某些Safari版本(包括5.0.2)会阻止跨域Cookie。
答案 0 :(得分:0)
最终,我发现没有办法真正解决这个问题。比如,一些旧版本的浏览器根本不支持在CORS请求中传递自定义标头。由于我们在身份验证中使用Json Web Tokens,我真的需要这样做。
因此,我在Application Request Routing (ARR)
中找到了这个IIS
模块,该模块使用URL Rewrite
引擎创建了reverse proxy
。更具体地说,将^/odata(.*)$
下的所有请求映射到我的后端web api主机。
以下是配置反向代理的高级步骤
保存后,规则将写入Web.config
<rewrite>
<rules>
<rule name="ODataApiReverseProxy" stopProcessing="true">
<match url="^odata(.*)$" />
<action type="Rewrite" url="http://webapi.host.tld/{R:0}" />
</rule>
</rules>
<outboundRules>
<rule name="ODataRewriteJson" preCondition="ResponseIsJson" patternSyntax="ExactMatch">
<match filterByTags="None" pattern="webapi.host.tld" />
<action type="Rewrite" value="client.host.tld" />
</rule>
<preConditions>
<preCondition name="ResponseIsJson">
<add input="{RESPONSE_CONTENT_TYPE}" pattern="^application/json" />
</preCondition>
</preConditions>
</outboundRules>
</rewrite>
现在,客户端将完全跳过CORS预检,因为它连接到同一主机。此外,ARR在配置,缓存,负载平衡,监控和管理等方面允许更多。