请在 401 时帮助测试 Firefox jQuery ajax 中的 CORS 问题
Posted
技术标签:
【中文标题】请在 401 时帮助测试 Firefox jQuery ajax 中的 CORS 问题【英文标题】:Please help test a CORS issue in Firefox jQuery ajax when 401 【发布时间】:2011-03-18 10:22:35 【问题描述】:这让我发疯了。
jQuery 1.4.2,Windows XP sp3
这是我的测试。
加载firefox 3.5+
http://plungjan.name/test/testcors.html
作品
将文件保存到硬盘并从那里运行
在我的办公室里,外部有效,内部无效
另外有趣的是,我不能同时跑两个。
背景: 我对使用CORS 的内部Web 服务执行GET。 请不发布任何关于 FF 自 v3.5 以来未处理跨域请求的答案,详细信息 here 和 here
它在 IE8 和 FF3.6.6 中从一台服务器到另一台服务器,现在几乎从文件系统 (file:///) 到服务。 仅来自文件系统和仅当 FF 3.6.6 需要协商(用户已经登录、授权并发送凭据!)协商后我是不是拿不到数据。 jQuery xhr 返回状态 0 并且没有数据/响应文本或其他 在我看来,jQuery 会做出反应并从 401 中保存 xhr,而不是稍后从 200 中保存
这是我在通信结束时提醒 XHR 对象时得到的结果:
Status:success
Data:[]
XHR:
some native functions,
readyState:4
status:0
responseXML:null
responseText:
withCredentials:true
如果我调用同一台服务器但不需要凭据,则数据会很好地跨域返回
所以通讯如下:
GET /restapplicationusingcors/authenticationneeded-internal/someid
Accept: application/json
Accept-Language: en
.
.
Origin: null
Cookie: LtpaToken=...
回报是
HTTP/1.1 401 Unauthorized
Server: Apache
Pragma: No-cache
Cache-Control: no-cache
Expires: Thu, 01 Jan 1970 01:00:00 CET
WWW-Authenticate: Negotiate
Connection: close
Transfer-Encoding: chunked
Content-Type: text/html
然后FF发送
GET /restapplicationusingcors/authenticationneeded-internal/someid HTTP/1.1
Host: myhost.myintranet.bla
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.6) Gecko/20100625 Firefox/3.6.6
Accept: application/json
Accept-Language: en
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 115
Connection: keep-alive
Origin: null
Cookie: LtpaToken=....
Authorization: Negotiate ....
并获得了我需要的文件,但在 FF 中无法获取:
HTTP/1.1 200 OK
Date: Tue, 20 Jul 2010 12:08:39 GMT
Pragma: No-cache
Cache-Control: no-cache, max-age=600, s-maxage=3600
Expires: Thu, 01 Jan 1970 01:00:00 CET
X-Powered-By: ...
Content-Disposition: inline;filename=nnnnnn.json
Content-Language: en
Access-Control-Allow-Origin: ...
Keep-Alive: timeout=6, max=70
Connection: Keep-Alive
Transfer-Encoding: chunked
Content-Type: application/json;charset=UTF-8
从服务器发送的数据不在 XHR 对象中
这是我的代码
function getJSON(url,func,lang)
accept = 'application/json';
lang=lang?lang:"*";
// gruesome hack to handle that APPENDS the mime header to */* !!!
// NOW HANDLED by first setting Accept to "" !!!
// if ($.browser.msie && url.indexOf('serveAsMime')==-1)
// url+= '?serveAsMime='+accept;
//
if (currentRequest != null) currentRequest.abort();
var requestObjectJSON =
url : url,
// dataType: "json",
method : 'get',
beforeSend: function(xhr)
xhr.setRequestHeader('Accept', ""); // IE hack
xhr.setRequestHeader('Accept', accept);
xhr.setRequestHeader('Accept-Language', lang);
if (url.indexOf('-internal') !=-1)
try
xhr.withCredentials = true;
alert('set credentials')
catch(e)
alert('cannot set xhr with credentials')
,
success: function(data,status,xhr)
var responseText = xhr.responseText;
var responseJSON = xhr.responseJSON;
var t = "";
try
for (var o in xhr) t += '\n'+o+':'+xhr[o];
catch(e)
if (e.message.indexOf('.channel')==-1)alert(e.message);
alert('Status:'+status+'\nData:['+data+']\nXHR:'+t);
func(responseText);
,
currentRequest = $.ajax(requestObjectJSON);
【问题讨论】:
“将文件保存到硬盘并从那里运行。在我的办公室里,外部工作正常,内部工作不工作。”我不明白。外部/内部什么有效? 重新标记。如果你使用更流行的标签,你会得到一些答案.. ;) ...和一个更具描述性的问题标题。 您是否检查过任何公司防火墙和/或安全软件?我遇到了 jQuery/Ajax 问题,公司安全措施正在检测 Ajax 请求并阻止它们——我最终遇到了与您所得到的类似的错误。这可能是一个远景,因为情况有些不同,但这是一个想法。 标题比一个星期更具描述性!标签具有代表性。 Nathan:防火墙完全没有问题,因为原始代码在防火墙内运行。 【参考方案1】:这是一个暗中的刺,因为我不完全理解您的问题,但我认为您可能对file:
URL 有问题,这些 URL 不被视为具有 任何 来源.我不确定是否可以可能从文件 URL 授权 CORS。
【讨论】:
这是真正的问题。但没有回答。 我这里有一个测试,现在通过身份验证根本不起作用:( talent-aid.org/test/testcors.html 我试过那个测试,老实说我不知道它是否失败,以及在什么情况下失败。我也不明白这是否是 file: 的问题,401 响应的问题,一般的身份验证问题,还是什么。你真的解释得不好。 对不起,我直到现在才看到这篇文章。我只能在 Intranet 上真正展示这一点。症状是它在 IE8 中完美运行,而 FF 仅在 html 位于文件系统上并且仅当其余调用需要身份验证时才会失败,例如当服务器 FIRST 返回 401 并且当它从浏览器获得身份验证并发送数据时,FF 或 jQuery 不会将数据传递给脚本,但仍会给出 OK 返回码......我希望人们看到标头和 XHR 返回代码已经将此识别为 FF 或 jQuery 中的错误,并且知道解决方法。谢谢 这听起来像是 Firefox 中的一个错误(或者可能是 jQuery,但我对此表示怀疑)。尝试在这里再次提出这个问题:support.mozilla.com/en-US/questions/new【参考方案2】:因此,您需要在模型/集合中设置 ajax 预过滤器才能使用 CORS。否则它不会发送 cookie。
$.ajaxPrefilter( function( options, originalOptions, jqXHR )
options.xhrFields =
withCredentials: true
;
);
我把它放在我的模型/集合初始化函数中。
【讨论】:
谢谢 - 一年后的现在有点没有实际意义。我感谢您的努力,并希望它对其他人有所帮助。我不需要代码也不需要服务器来测试它【参考方案3】:这些是使 CORS 与安全服务一起工作需要满足的条件:
服务响应应包含标头Access-Control-Allow-Credentials: true
(请参阅Requests with credentials 和Cannot use wildcard in Access-Control-Allow-Origin when credentials flag is true)。
服务响应标头Access-Control-Allow-Origin
不应为*
。这个想法是返回客户端在标头Origin
中传递的值(参见this post 中的示例)。
根据规范,OPTIONS
方法应返回 HTTP 代码 200,因此无法保护(请参阅The CORS)。
对于需要将某些请求标头传递给服务的方法PUT
/POST
(如Content-Type
或Accept
),这些标头需要在Access-Control-Allow-Headers
中列出(请参阅jQuery AJAX fails to work when headers are specified)李>
javascript 应设置此 XMLHttpRequest
属性:xhr.withCredentials = true;
(由 Kirby 回答)
Apache 的总体配置:
# Static content:
SetEnvIf Request_URI ".*" no-jk
# RESTful service:
SetEnvIf Request_URI "^/backend/" !no-jk
SetEnvIf Request_Method "OPTIONS" no-jk
# Fallback value:
SetEnv http_origin "*"
SetEnvIf Origin "^https?://(localhost|.*\.myconpany\.org)(:[0-9]+)?$" http_origin=$0
Header set Access-Control-Allow-Credentials "true"
Header set Access-Control-Allow-Origin "%http_origine"
Header set Access-Control-Allow-Methods "GET,POST,PUT,DELETE"
Header set Access-Control-Allow-Headers "Content-Type, Accept"
JkMount /* loadbalancer
【讨论】:
【参考方案4】:带有file://
的CORS
如果您在允许来自file://
协议的来源时遇到问题,根据The Web Origin Concept,它应该以与任何其他来源相同的方式完成。 我找不到有关浏览器支持的信息,但我认为每个支持 CORS 的浏览器也都支持这个。
Web Origin Concept 告诉我们有关文件 URI 方案的以下内容:
4. If uri-scheme is "file", the implementation MAY return an
implementation-defined value.
NOTE: Historically, user agents have granted content from the
file scheme a tremendous amount of privilege. However,
granting all local files such wide privileges can lead to
privilege escalation attacks. Some user agents have had
success granting local files directory-based privileges, but
this approach has not been widely adopted. Other user agents
use globally unique identifiers for each file URI, which is
the most secure option.
根据wikipedia文件URI方案的域是localhost。地址栏可以省略它,但我不认为它在允许来源标头中可以省略。因此,如果您的浏览器实现允许使用文件 URI 方案的来源,那么您应该将 file://localhost
添加到您允许的来源,之后一切都应该正常工作。
本来应该是这样的,现在来看看现实吧:
我用当前的 firefox 29.0.1 进行了测试,但它不起作用。但是,file://
协议通过此实现转换为 null
来源。因此,通过 Firefox,null
可以工作。我尝试使用更广泛的域列表,但我没有设法允许多个域。 Firefox 目前似乎不支持包含多个域的列表。
我使用 chrome 35.0.1916 进行了测试,它的工作方式与 Firefox 相同。
我使用 msie 11.0.9600 进行了测试。根据文件协议的请求,它总是显示一个allow blocked content
按钮,即使不允许空源。在其他域中,它的工作方式与以前的浏览器相同。
HTTP 基本认证:
我尝试使用 php 和 HTTP 基本身份验证的凭据部分。
http://test.loc登录时显示:-),未授权时显示:-(。
<?php
function authorized()
if (empty($_SERVER['PHP_AUTH_USER']) || empty($_SERVER['PHP_AUTH_PW']))
return false;
return ($_SERVER['PHP_AUTH_USER'] == 'username' && $_SERVER['PHP_AUTH_PW'] == 'password');
function unauthorized()
header('HTTP/1.1 401 Unauthorized');
header('WWW-Authenticate: Basic realm="Restricted Area"');
echo '<a href="http://test.loc">:-(</a>';
if (!isset($_GET['logout']) && authorized())
echo '<a href="http://test.loc?logout=1">:-)</a>';
else
unauthorized();
所以这段代码通过登录和注销来改变位置。
带有 HTTP 基本身份验证的跨域 CORS
http://todo.loc通过跨域 XHR 获取http://test.loc 的内容并显示出来。
cross domain ajax<br />
<script>
var xhr = new XMLHttpRequest();
xhr.open('GET', "http://test.loc", true);
xhr.withCredentials = true;
xhr.onreadystatechange = function ()
if (xhr.readyState==4)
document.body.innerHTML += xhr.responseText;
;
xhr.send();
</script>
需要http://test.loc的标题:
Access-Control-Allow-Origin: http://todo.loc
Access-Control-Allow-Credentials: true
带有 HTTP 基本身份验证的跨方案 CORS
file:///path/x.html用cross scheme XHR 获取http://test.loc 的内容并显示出来。 em>
cross scheme ajax<br />
<script>
var xhr = new XMLHttpRequest();
xhr.open('GET', "http://test.loc", true);
xhr.withCredentials = true;
xhr.onreadystatechange = function ()
if (xhr.readyState==4)
document.body.innerHTML += xhr.responseText;
;
xhr.send();
</script>
需要http://test.loc的标题:
Access-Control-Allow-Origin: null
Access-Control-Allow-Credentials: true
结论:
我使用从 file://
调用的凭据测试了 cross-sheme CORS,它在 firefox、chrome 和 msie 中运行良好。
【讨论】:
来自文件协议的来源为空白。不再重要 这是 FX 3.5 中的一个非常古老的问题 - 我们现在拥有 FX27 并改变了我们使用它的方式。不过谢谢 是的,我刚刚发现现在每个浏览器都使用null
origin。以上是关于请在 401 时帮助测试 Firefox jQuery ajax 中的 CORS 问题的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 Windows 身份验证和 Firefox 运行 Selenium NUnit 测试?
jquery $.ajax 在 Chrome 或 Firefox 中调用会导致 401 未经授权的响应,但在 IE 中有效
JHipster:测试微服务时收到 401 Unauthorized