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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/5202296/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 16:09:31  来源:igfitidea点击:

Add a "hook" to all AJAX requests on a page

javascriptajaxxmlhttprequest

提问by Yuliy

I'd like to know if it's possible to "hook" into every single AJAX request (either as it's about to get sent, or on events) and perform an action. At this point I'm assuming that there are other third-party scripts on the page. Some of these might use jQuery, while others do not. Is this possible?

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

回答by John Culviner

NOTE: The accepted answer does not yield the actual response because it is getting called too early.

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

You can do this which will generically intercept anyAJAX globally and not screw up any callbacks etc. that maybe have been assigned by any third party AJAX libraries.

您可以这样做,这将在全局范围内拦截任何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);
    };
})();

Some more docs of what you can do here with the addEventListener API here:

您可以在此处使用 addEventListener API 执行的操作的更多文档:

https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest#Monitoring_progress

https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest#Monitoring_progress

(Note this doesn't work <= IE8)

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

回答by meouw

Inspired by aviv's answer, I did a little investigating and this is what I came up with.
I'm not sure that it's all that usefulas per the comments in the script and of course will only work for browsers using a native XMLHttpRequest object.
I think it will work if javascript libraries are in use as they will use the native object if possible.

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

回答by jondavidjohn

Since you mention jquery, I know jquery offers a .ajaxSetup()method that sets global ajax options that include the event triggers like success, error, and beforeSend- which is what sounds like what you are looking for.

既然您提到了 jquery,我知道 jquery 提供了.ajaxSetup()一种设置全局 ajax 选项的方法,其中包括诸如、 和- 之类的事件触发器success,这听起来像您正在寻找的内容。errorbeforeSend

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

of course you would need to verify jQuery availability on any page you attempt to use this solution on.

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

回答by Mohamed Selim

I've found a good library on Github that does the job well, you have to include it before any other js files

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

https://github.com/jpillora/xhook

https://github.com/jpillara/xhook

here is an example that adds an http header to any incoming response

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

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

回答by aviv

There is a trick to do it.

有一个技巧可以做到。

Before all scripts running, take the original XHMHttpReuqest object and save it in a different var. Then override the original XMLHttpRequest and direct all calls to it via your own object.

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

Psuedo code:

伪代码:

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

回答by heroin

Using the answer of "meouw" I suggest to use the following solution if you want to see results of request

使用“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 );
    }
});

回答by heroin

In addition to meouw's answer, I had to inject code into an iframe which intercepts XHR calls, and used the above answer. However, I had to change

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

XMLHttpRequest.prototype.send = function(){

To:

到:

XMLHttpRequest.prototype.send = function(body)

And I had to change

我不得不改变

oldSend.apply(this, arguments);

To:

到:

oldSend.call(this, body);

This was necessary to get it working in IE9 with IE8 document mode. If this modification was not made, some call-backs generated by the component framework (Visual WebGUI) did not work. More info at these links:

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

Without these modifications AJAX postbacks did not terminate.

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

回答by Vladimir Miroshnichenko

jquery...

查询...

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