11

我在玩这个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请求。这是萤火虫的控制台显示的:

    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 规范页面中,hello world 片段使用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.DONE. DONE值为 4,这是我在日志中看到的。因此,如果这是与 XSS 相关的问题,并且浏览器阻止我连接到不同的域,那么为什么会建立实际连接并收到 DONE 状态???

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


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


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

4

3 回答 3

11

看起来确实是 XSS 问题,Firefox 阻止了onload调用。我仍然无法理解为什么 http 网络请求实际上正在完成并且onreadystatechange正在使用DONEreadyState 进行调用。

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

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

于 2013-02-06T13:00:16.280 回答
1

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

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

于 2019-09-16T07:29:54.130 回答
0

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/

于 2017-12-21T22:19:48.640 回答