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

问题描述 投票:0回答:9

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

javascript ajax xmlhttprequest
9个回答
178
投票

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

注意2:这不适用于本机

fetch
,但如果需要,您可以使用类似的代理方法

您可以这样做,这通常会全局拦截any 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)


122
投票

受到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
});

23
投票

既然你提到了jquery,我知道jquery提供了一个

.ajaxSetup()
方法来设置全局ajax选项,其中包括像
success
error
beforeSend
这样的事件触发器——这听起来像是你正在寻找的东西。

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

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


9
投票

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

https://github.com/jpillora/xhook

这是一个向任何传入响应添加 http 标头的示例

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

8
投票

使用“meouw”的答案,如果您想查看请求结果,我建议使用以下解决方案

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 );
    }
});

8
投票

有一个技巧可以做到这一点。

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

伪代码:

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

6
投票

除了 meouw 的答案之外,我还必须将代码注入到拦截 XHR 调用的 iframe 中,并使用上面的答案。然而我不得不改变

XMLHttpRequest.prototype.send = function(){

致:

XMLHttpRequest.prototype.send = function(body)

我必须改变

oldSend.apply(this, arguments);

致:

oldSend.call(this, body);

这是让它在 IE9 和 IE8 文档模式中工作所必需的。如果不进行此修改,组件框架 (Visual WebGUI) 生成的某些回调将不起作用。更多信息请访问这些链接:

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


3
投票

jquery...

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

0
投票

查看 jquery ajax 事件。你可以这样做:

$(document).on("ajaxSend", function (e) {
    console.log("before request is sent");
}).on("ajaxComplete", function (e) {
    console.log("after success or error");
}).on("ajaxSuccess ", function (e) {
    console.log("on success");
}).on("ajaxError ", function (e) {
    console.log("on error");
});
© www.soinside.com 2019 - 2024. All rights reserved.