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

时间:2011-03-05 07:04:22

标签: javascript ajax xmlhttprequest

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

9 个答案:

答案 0 :(得分:106)

受到aviv's answer的启发,我做了一些调查,这就是我想出来的 根据脚本中的注释,我不确定它是否有用,当然仅适用于使用原生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
});

答案 1 :(得分:93)

如果您不必支持&lt; = IE8,您可以执行此操作,这样可以全局拦截任何 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

答案 2 :(得分:20)

由于你提到了jquery,我知道jquery提供了一个.ajaxSetup()方法来设置包含successerrorbeforeSend等事件触发器的全局ajax选项 - 听起来就像你在寻找的东西。

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

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

答案 3 :(得分:9)

有一个技巧可以做到。

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

Psuedo代码:

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

答案 4 :(得分:7)

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

https://github.com/jpillora/xhook

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

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

答案 5 :(得分:5)

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

答案 6 :(得分:3)

除了meouw的答案之外,我不得不将代码注入拦截XHR调用的iframe,并使用上述答案。但是,我不得不改变

XMLHttpRequest.prototype.send = function(){

要:

XMLHttpRequest.prototype.send = function(arguments)

我不得不改变

oldSend.apply(this, arguments);

要:

oldSend.call(this, arguments);

这对于使用 IE8文档模式在IE9中运行是必要的。如果未进行此修改,则组件框架(Visual WebGUI)生成的某些回调不起作用。有关这些链接的更多信息:

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

答案 7 :(得分:3)

... jquery的

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

答案 8 :(得分:1)

Ajax-hook是一个用于挂钩全局XMLHttpRequest对象的开源库,并更改了默认的Ajax请求和响应。 github:https://github.com/wendux/Ajax-hook,例如:

hookAjax({

  //hook callbacks
  onreadystatechange:function(xhr){
   console.log("onreadystatechange called: %O",xhr)
  },

  onload:function(xhr){
   console.log("onload called: %O",xhr)
  },

  //hook function
  open:function(arg,xhr){
   console.log("open called: method:%s,url:%s,async:%s",arg[0],arg[1],arg[2])
  }

})