编辑:请参阅下面的第二个代码选项(它经过测试并且有效)。第一个有一些限制。
由于您无法修改任何这些函数,因此您似乎必须遵循 XMLHttpRequest 原型。这是一个想法(未经测试,但你可以看到方向):
(function() {
var open = XMLHttpRequest.prototype.open;
XMLHttpRequest.prototype.open = function(method, url, async, user, password) {
var oldReady;
if (async) {
oldReady = this.onreadystatechange;
// override onReadyStateChange
this.onreadystatechange = function() {
if (this.readyState == 4) {
// this.responseText is the ajax result
// create a dummay ajax object so we can modify responseText
var self = this;
var dummy = {};
["statusText", "status", "readyState", "responseType"].forEach(function(item) {
dummy[item] = self[item];
});
dummy.responseText = '{"msg": "Hello"}';
return oldReady.call(dummy);
} else {
// call original onreadystatechange handler
return oldReady.apply(this, arguments);
}
}
}
// call original open method
return open.apply(this, arguments);
}
})();
这为 XMLHttpRequest 做了一个猴子补丁open()
方法,然后当为异步请求调用该方法时,它会为 onReadyStateChange 处理程序执行猴子补丁,因为应该已经设置了该处理程序。然后,该修补函数可以在调用原始 onReadyStateChange 处理程序之前查看responseText,以便可以为其分配不同的值。
并且,最后因为.responseText
是只读的,这会在调用之前替换一个虚拟的 XMLHttpResponse 对象onreadystatechange
处理程序。这并非在所有情况下都有效,但如果 onreadystatechange 处理程序使用this.responseText
得到回应。
并且,这里尝试将 XMLHttpRequest 对象重新定义为我们自己的代理对象。因为它是我们自己的代理对象,所以我们可以设置responseText
财产为我们想要的任何东西。对于除onreadystatechange
,该对象只是将 get、set 或函数调用转发给真正的 XMLHttpRequest 对象。
(function() {
// create XMLHttpRequest proxy object
var oldXMLHttpRequest = XMLHttpRequest;
// define constructor for my proxy object
XMLHttpRequest = function() {
var actual = new oldXMLHttpRequest();
var self = this;
this.onreadystatechange = null;
// this is the actual handler on the real XMLHttpRequest object
actual.onreadystatechange = function() {
if (this.readyState == 4) {
// actual.responseText is the ajax result
// add your own code here to read the real ajax result
// from actual.responseText and then put whatever result you want
// the caller to see in self.responseText
// this next line of code is a dummy line to be replaced
self.responseText = '{"msg": "Hello"}';
}
if (self.onreadystatechange) {
return self.onreadystatechange();
}
};
// add all proxy getters
["status", "statusText", "responseType", "response",
"readyState", "responseXML", "upload"].forEach(function(item) {
Object.defineProperty(self, item, {
get: function() {return actual[item];}
});
});
// add all proxy getters/setters
["ontimeout, timeout", "withCredentials", "onload", "onerror", "onprogress"].forEach(function(item) {
Object.defineProperty(self, item, {
get: function() {return actual[item];},
set: function(val) {actual[item] = val;}
});
});
// add all pure proxy pass-through methods
["addEventListener", "send", "open", "abort", "getAllResponseHeaders",
"getResponseHeader", "overrideMimeType", "setRequestHeader"].forEach(function(item) {
Object.defineProperty(self, item, {
value: function() {return actual[item].apply(actual, arguments);}
});
});
}
})();
工作演示:http://jsfiddle.net/jfriend00/jws6g691/ http://jsfiddle.net/jfriend00/jws6g691/
我在最新版本的 IE、Firefox 和 Chrome 中尝试过,它可以处理简单的 ajax 请求。
注意:我还没有研究过 Ajax 的所有高级方法(如二进制数据、上传等),以了解该代理是否足够彻底以完成所有这些工作(我猜可能还没有)无需进一步的工作,但它正在满足基本请求,因此看起来这个概念是有能力的)。
其他失败的尝试:
尝试从 XMLHttpRequest 对象派生,然后用我自己的构造函数替换构造函数,但这不起作用,因为真正的 XMLHttpRequest 函数不允许您将其作为函数调用来初始化我的派生对象。
尝试只是覆盖onreadystatechange
处理程序和更改.responseText
,但该字段是只读的,因此您无法更改它。
尝试创建一个虚拟对象作为this
调用时的对象onreadystatechange
,但是很多代码没有引用this
,而是将实际对象保存在闭包中的局部变量中 - 从而击败了虚拟对象。