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

IT技术 javascript ajax xmlhttprequest
2021-02-03 22:11:21

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

6个回答

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

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

花了很多天才找到这个。谢谢你的这个天才。
2021-03-15 22:11:21
我尝试了很多答案,这与 WKWebView 完美配合。我在使用 Ajax 事件时遇到了麻烦,因为在我调用evaluateJavascript 或使用 addUserScript 之前可能没有加载 jQuery。谢谢!
2021-03-16 22:11:21
这对你来说可能会感觉很旧,但你应该得到所有的爱。我被深深地困住了。谢谢一堆。
2021-03-18 22:11:21
仅仅是因为我对此进行了一些搜索。"load"事件仅在成功时调用。如果您不关心结果(只是查询确实结束了),您可以使用该"loadend"事件
2021-03-30 22:11:21
谢谢!那是完美的。我只修改了一点:this.status在这种情况下,200如果请求正常,则返回服务器状态,如果未找到元素,则返回 404,500 等。但是代码完美运行。
2021-04-03 22:11:21

受到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
});
console.log( xhr.responseText ) 是一个空字符串,因为此时 xhr 是空的。如果您将 xhr 变量传递给全局变量并设置延迟几秒钟,您将能够直接访问属性
2021-03-11 22:11:21
根据您的实现,我在 NPM 上发布了一些可以同时处理请求和响应的内容!github.com/slorber/ajax-interceptor
2021-03-16 22:11:21
扩展此响应以支持请求后挂钩会很好
2021-03-22 22:11:21
@ucheng 如果我们添加 xhr 的 onreadystatechange,它会不会覆盖原来的就绪状态更改方法,最好使用 xhrObj.addEventListener("load", fn)
2021-03-26 22:11:21
很好的答案。如果要获取响应数据,请检查状态更改时的就绪状态和状态。xhr.onreadystatechange=function(){ if ( xhr.readyState == 4 && xhr.status == 200 ) { console.log(JSON.parse(xhr.responseText)); } }
2021-04-03 22:11:21

既然你提到的jQuery,我知道jQuery提供了一个.ajaxSetup()方法,其中包括事件触发的套装全局AJAX选项successerror以及beforeSend-这是什么听起来像你在找什么。

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

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

感谢您的建议,但不幸的是,这不会拦截未使用​​ AJAX 的 AJAX 调用。
2021-03-19 22:11:21
非常有帮助。想补充一下,另一个触发器是 statusCode。通过插入类似 statusCode: { 403: function() { error msg } 之类的东西,您可以向所有 ajax 函数提供全局 auth/perms/role 检查,而无需重新编写单个 .ajax 请求。
2021-03-28 22:11:21
在今日新闻中:被不使用 AJAX 的 AJAX 调用杀死的独角兽
2021-04-06 22:11:21
他的意思不是 jquery AJAX 对象。但即便如此,你也会每次都使用相同的 jquery 实例
2021-04-10 22:11:21

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

https://github.com/jpillara/xhook

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

xhook.after(function(request, response) {
  response.headers['Foo'] = 'Bar';
});
这非常适合我的特定需求:在 Wordpress 中,从 Events Organizer 插件完整日历中过滤事件
2021-03-12 22:11:21
不适用于所有请求,一些 fetch 和 xhr 可以,但例如它不能从 google recaptcha 中捕获 xhr
2021-03-20 22:11:21
@SergioQuintero XHR 接口的任何覆盖仅发生在该文档中,而不是在浏览器中全局发生,因为这将是一个巨大的安全/隐私漏洞。reCAPTCHA 在 iframe 中运行,您无法在其中运行覆盖。
2021-03-23 22:11:21
@SergioQuintero:我认为这是您的 GitHub 问题:github.com/jpillora/xhook/issues/102考虑在此处删除您的评论,因为这不是图书馆的问题。
2021-03-25 22:11:21
很棒的一个!但即使使用人行横道最新的 chrome 网络视图插件,也无法在 Cordova 应用程序上工作!
2021-04-02 22:11:21

有一个技巧可以做到。

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

伪代码:

 var savd = XMLHttpRequest;
 XMLHttpRequest.prototype = function() {
         this.init = function() {
         }; // your code
         etc' etc'
 };
这个答案不太正确,如果您更改对象的原型,即使是保存的原型也会更改。此外,整个原型将被替换为一个函数,该函数将中断所有 ajax 请求。不过,它确实激励我提供答案。
2021-03-23 22:11:21