我正在玩这个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代码片段使用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状态???
更新:
我已经将URL更改为我的域(localhost)中的一个,并且错误消失但onload
函数仍未被调用。在IE8中测试并不起作用。在Chrome中测试并且有效。怎么样?
更新2:
在Firefox中再次测试,现在它可以工作。可能旧的页面仍然被缓存,这就是为什么我不能立刻注意到它。在IE8中仍然失败,我将尝试在更新的版本中测试它。
答案 0 :(得分:9)
看起来它确实是一个XSS问题,Firefox正在阻止onload
调用。我仍然无法理解为什么http网络请求实际上已经完成,onreadystatechange
正在使用DONE
readyState调用。
我将URL更改为同一域中的另一个,现在它可以在Firefox中运行(在一些与缓存相关的错误尝试之后)和Chrome中。它仍然无法在IE8中运行,尽管official docs表示支持它。我发现this SO answer表明了其他情况。看起来onload
函数是一种更现代的便捷方法,而检查结果的旧方法是使用onreadystatechange
代替。
我想我会接受这个答案作为解决方案,除非提供更详细的答案。
答案 1 :(得分: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;
};
答案 2 :(得分:0)
onload
处理程序由于其他原因而不会被调用,我在这里添加它只是为了对其他引用此页面的人有所帮助。
如果HTTP响应格式错误,则onload
处理程序也不会被调用。例如,在Content-Length
标头中通告长度为14的10字节纯文本响应将不会调用onload
处理程序。在开始用测试存根替换后端单元之前,我在客户机代码上浪费了时间。