未调用 XmlHttpRequest.onload

Posted

技术标签:

【中文标题】未调用 XmlHttpRequest.onload【英文标题】:XmlHttpRequest.onload not called 【发布时间】:2013-01-21 13:42:09 【问题描述】:

我正在玩这个XmlHttpRequest 的东西。在一些教程和书籍中,当请求完成时调用的是onload 函数。在我的小实验中,这个函数永远不会被调用。这是我的代码:

    window.onload = function() 
        var url = "http://www.google.com";
        var request = new XMLHttpRequest();


        request.onload = function() 
            var state = this.readyState;
            var responseCode = request.status;
            console.log("request.onload called. readyState: " + state + "; status: " + responseCode);

            if (state == this.DONE && responseCode == 200) 
                var responseData = this.responseText;
                alert("Success: " + responseData.length  + " chars received.");
            
        ;

        request.error = function(e) 
            console.log("request.error called. Error: " + e);
        ;

        request.onreadystatechange = function()
            console.log("request.onreadystatechange called. readyState: " + this.readyState);
        ;

        request.open("GET", url);
        request.send(null);
    ;

我正在上一个 Firefox 版本(今天刚刚更新)上对此进行测试。 onload 中的日志行从不打印,我在第一行设置的断点也从不命中。但是onreadystatechange函数被调用了两次,实际上是发起了http请求。这是 firebug 的控制台显示的内容:

    request.onreadystatechange called. readyState: 1
    GET http://www.google.com/    302 Found    174ms
    request.onreadystatechange called. readyState: 4
    NS_ERROR_FAILURE: Failure
        request.send(null);

send 行中有错误。我尝试将其更改为 request.send(),结果相同。

起初我以为这可能是浏览器试图阻止 XSS,所以我将我的 html 驱动程序页面移动到我的开发机器中的一个 Tomcat 实例,但结果是一样的。

这个函数是否保证被调用?正如我上面所说,在大多数教程中都很常见,但另一方面,在 W3C spec page 中,hello world sn-p 使用 onreadystatechange 代替:

    function processData(data) 
      // taking care of data
    

    function handler() 
      if(this.readyState == this.DONE) 
        if(this.status == 200 &&
           this.responseXML != null &&
           this.responseXML.getElementById('test').textContent) 
          // success!
          processData(this.responseXML.getElementById('test').textContent);
          return;
        
        // something went wrong
        processData(null);
      
    

    var client = new XMLHttpRequest();
    client.onreadystatechange = handler;
    client.open("GET", "unicorn.xml");
    client.send();

它检查readyState == this.DONEDONE 的值为 4,这是我在日志中看到的。因此,如果这是与 XSS 相关的问题,并且浏览器阻止我连接到不同的域,那么为什么会建立实际连接并收到 DONE 状态???

PS:是的,我知道有强大的库可以轻松做到这一点,但我仍然是 javascript 菜鸟,所以我想先了解底层。


更新: 我已将 URL 更改为我的域 (localhost) 中的一个,错误消失了,但仍然没有调用 onload 函数。在 IE8 中测试并不起作用。在 Chrome 中测试并有效。怎么样?


更新 2: 在 Firefox 中再次测试,现在它可以工作了。可能旧页面仍在缓存中,所以我无法立即注意到它。在 IE8 中仍然失败,我将尝试在更新的版本中对其进行测试。

【问题讨论】:

请注意,jQuery 已经解决了这个问题。即使你不想使用它,你也可以研究它的代码。 这是工作中的 webdevs 刚刚告诉我的。我在实际项目中使用它没有问题。我应该寻找哪个源文件? jQuery 被包裹在文件中。我不建议使用缩小版,因为它更难阅读。寻找ajax 方法,如果需要,挖掘。 我直接在 git hub 上阅读。看起来它也使用 onload,但似乎代码以更好的方式处理 XSS。 将 request.open 移到 request.load 上方 【参考方案1】:

看起来确实是 XSS 问题,Firefox 阻止了 onload 调用。我仍然无法理解为什么 http 网络请求实际上正在完成,而 onreadystatechangeDONE readyState 调用。

我将 URL 更改为同一域中的另一个 URL,现在它可以在 Firefox(经过一些与缓存相关的错误尝试后)和 Chrome 中工作。尽管official docs 说它受支持,但它仍然无法在 IE8 中运行。我发现this SO answer 另有说明。看起来onload 函数是一种更现代的便捷方法,而检查结果的旧方法是改用onreadystatechange

我想我会接受这个答案作为解决方案,除非提供更详细的答案。

【讨论】:

一直在寻找同样的问题。想知道是否有新发现。【参考方案2】:

onload 处理程序不会因为另一个原因被调用,我在这里添加它只是为了对引用此页面的其他人有所帮助。

如果 HTTP 响应格式错误,onload 处理程序也不会被调用。例如,在 Content-Length 标头中通告长度为 14 的 10 字节的纯文本响应将不会调用 onload 处理程序。在开始用测试存根替换后端单元之前,我在客户端代码上浪费了数小时。

【讨论】:

【参考方案3】:

IE 有不同的方法来创建 xmlhttprequest。

function createCORSRequest(method, url) 
  var xhr = new XMLHttpRequest();
  if ("withCredentials" in xhr) 

    // Check if the XMLHttpRequest object has a "withCredentials" property.
    // "withCredentials" only exists on XMLHTTPRequest2 objects.
    xhr.open(method, url, true);

   else if (typeof XDomainRequest != "undefined") 

    // Otherwise, check if XDomainRequest.
    // XDomainRequest only exists in IE, and is IE's way of making CORS requests.
    xhr = new XDomainRequest();
    xhr.open(method, url);

   else 

    // Otherwise, CORS is not supported by the browser.
    xhr = null;

  
  return xhr;
;

同这篇文章:https://www.html5rocks.com/en/tutorials/cors/

【讨论】:

以上是关于未调用 XmlHttpRequest.onload的主要内容,如果未能解决你的问题,请参考以下文章

在 Jest 中测试 XMLHttpRequest onload() 回调功能

未完全加载单元格时未调用 didSelectItemAtIndexPath

数据流 - 未调用函数 - 错误 - 未定义名称

numberOfRowsInSection 已调用但 cellForRowAt 未调用

调用 textFieldShouldBeginEditing,未调用 textFieldDidBeginEditing

JQuery:未捕获的类型错误:无法读取未定义的属性“调用”