为页面上的所有 AJAX 请求添加一个“钩子”

我想知道是否有可能“挂钩”到每一个 AJAX 请求(无论是即将发送的,还是事件)并执行一个操作。此时,我假设页面上还有其他第三方脚本。其中一些可能会使用 jQuery,而另一些则不会。这可能吗?

110223 次浏览

做这件事是有诀窍的。

在所有脚本运行之前,获取原始的 XHMHttpReuqest 对象并将其保存到另一个变量中。然后覆盖原始的 XMLHttpRequest 并通过您自己的对象直接调用它。

伪装代码:

 var savd = XMLHttpRequest;
XMLHttpRequest.prototype = function() {
this.init = function() {
}; // your code
etc' etc'
};

既然你提到了 jquery,我知道 jquery 提供了一个设置全局 ajax 选项的 .ajaxSetup()方法,这些选项包括事件触发器,比如 successerrorbeforeSend——这听起来就是你想要的。

$.ajaxSetup({
beforeSend: function() {
//do stuff before request fires
}
});

当然,您需要在试图使用该解决方案的任何页面上验证 jQuery 的可用性。

Aviv 的回答的启发,我做了一些调查,得出了以下结论。
根据脚本中的注释,当然还有 将只适用于使用本机 XMLHttpRequest 对象的浏览器,我不确定它是否完全有用。
我认为如果使用 javascript 库,那么它将会工作,因为如果可能的话,它们将使用本机对象。

function addXMLRequestCallback(callback){
var oldSend, i;
if( XMLHttpRequest.callbacks ) {
// we've already overridden send() so just add the callback
XMLHttpRequest.callbacks.push( callback );
} else {
// create a callback queue
XMLHttpRequest.callbacks = [callback];
// store the native send()
oldSend = XMLHttpRequest.prototype.send;
// override the native send()
XMLHttpRequest.prototype.send = function(){
// process the callback queue
// the xhr instance is passed into each callback but seems pretty useless
// you can't tell what its destination is or call abort() without an error
// so only really good for logging that a request has happened
// I could be wrong, I hope so...
// EDIT: I suppose you could override the onreadystatechange handler though
for( i = 0; i < XMLHttpRequest.callbacks.length; i++ ) {
XMLHttpRequest.callbacks[i]( this );
}
// call the native send()
oldSend.apply(this, arguments);
}
}
}


// e.g.
addXMLRequestCallback( function( xhr ) {
console.log( xhr.responseText ); // (an empty string)
});
addXMLRequestCallback( function( xhr ) {
console.dir( xhr ); // have a look if there is anything useful here
});

除了 meouw 的回答之外,我还必须将代码注入到一个可以拦截 XHR 调用的 iframe 中,并使用上面的回答。但是,我必须改变吗

XMLHttpRequest.prototype.send = function(){

致:

XMLHttpRequest.prototype.send = function(body)

我必须改变

oldSend.apply(this, arguments);

致:

oldSend.call(this, body);

这对于在 IE9中使用 IE8文档模式来说是必要的。如果不进行此修改,则组件框架(VisualWebGUI)生成的一些回调将不起作用。更多信息请点击以下链接:

如果没有这些修改,AJAX 回发不会终止。

Jquery...

<script>
$(document).ajaxSuccess(
function(event, xhr, settings){
alert(xhr.responseText);
}
);
</script>

如果您希望看到请求的结果,我建议使用“喵”的答案使用以下解决方案

function addXMLRequestCallback(callback) {
var oldSend, i;
if( XMLHttpRequest.callbacks ) {
// we've already overridden send() so just add the callback
XMLHttpRequest.callbacks.push( callback );
} else {
// create a callback queue
XMLHttpRequest.callbacks = [callback];
// store the native send()
oldSend = XMLHttpRequest.prototype.send;
// override the native send()
XMLHttpRequest.prototype.send = function() {
// call the native send()
oldSend.apply(this, arguments);


this.onreadystatechange = function ( progress ) {
for( i = 0; i < XMLHttpRequest.callbacks.length; i++ ) {
XMLHttpRequest.callbacks[i]( progress );
}
};
}
}
}


addXMLRequestCallback( function( progress ) {
if (typeof progress.srcElement.responseText != 'undefined' &&                        progress.srcElement.responseText != '') {
console.log( progress.srcElement.responseText.length );
}
});

注意: 接受的答案不会产生实际的响应,因为它被调用得太早了。

你可以这样做,这将通常拦截 任何 AJAX 全局,不搞砸任何回调等,可能已经分配给任何第三方 AJAX 库。

(function() {
var origOpen = XMLHttpRequest.prototype.open;
XMLHttpRequest.prototype.open = function() {
console.log('request started!');
this.addEventListener('load', function() {
console.log('request completed!');
console.log(this.readyState); //will always be 4 (ajax is completed successfully)
console.log(this.responseText); //whatever the response was
});
origOpen.apply(this, arguments);
};
})();

这里有一些关于使用 addEventListener API 可以做什么的文档:

Https://developer.mozilla.org/en-us/docs/web/api/xmlhttprequest/using_xmlhttprequest#monitoring_progress

(注意,这不起作用 < = IE8)

我在 Github 上找到了一个很好的库,可以很好地完成这项工作,您必须在其他任何 js 文件之前包含它

Https://github.com/jpillora/xhook

下面是一个将 http 头添加到任何传入响应的示例

xhook.after(function(request, response) {
response.headers['Foo'] = 'Bar';
});