请在 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-TypeAccept),这些标头需要在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.htmlcross 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

无法在无头模式下运行 Firefox

未经授权的用户在使用 phpunit 测试时返回状态 500 而不是 401

animate.css 在 Firefox 和 chrome 中加载双倍时间