Добавьте «крючок» ко всем запросам AJAX на странице - PullRequest
92 голосов
/ 05 марта 2011

Я хотел бы знать, можно ли "подключиться" к каждому отдельному AJAX-запросу (как при отправке, так и по событиям) и выполнить действие. На данный момент я предполагаю, что на странице есть другие сторонние скрипты. Некоторые из них могут использовать jQuery, а другие нет. Возможно ли это?

Ответы [ 8 ]

106 голосов
/ 05 марта 2011

Вдохновленный ответом Авива , я провел небольшое расследование, и вот что я придумал.
Я не уверен, что это все так полезно в соответствии скомментарии в сценарии и, конечно, будут работать только для браузеров, использующих собственный объект 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
});
98 голосов
/ 08 декабря 2014

ПРИМЕЧАНИЕ. Принятый ответ не дает фактического ответа, поскольку его вызывают слишком рано.

Вы можете сделать это, что в общем случае будет перехватывать любой 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);
    };
})();

Еще несколько документов о том, что вы можете сделать здесь с помощью API addEventListener здесь:

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

(обратите внимание, это не работает <= IE8) </p>

20 голосов
/ 05 марта 2011

Поскольку вы упоминаете jquery, я знаю, что jquery предлагает метод .ajaxSetup(), который устанавливает глобальные параметры ajax, которые включают в себя триггеры событий, такие как success, error и beforeSend - что звучит так, как вы ищете для.

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

конечно, вам нужно будет проверить доступность jQuery на любой странице, на которой вы пытаетесь использовать это решение.

9 голосов
/ 05 марта 2011

Есть хитрость, чтобы сделать это.

Перед запуском всех сценариев возьмите оригинальный объект XHMHttpReuqest и сохраните его в другой переменной. Затем переопределите исходный XMLHttpRequest и направьте все вызовы к нему через свой собственный объект.

Код Psuedo:

 var savd = XMLHttpRequest;
 XMLHttpRequest.prototype = function() {
         this.init = function() {
         }; // your code
         etc' etc'
 };
8 голосов
/ 08 сентября 2016

Я нашел хорошую библиотеку на Github, которая хорошо справляется со своей задачей, вы должны включить ее перед любыми другими js-файлами

https://github.com/jpillora/xhook

, вот пример, который добавляетЗаголовок http для любого входящего ответа

xhook.after(function(request, response) {
  response.headers['Foo'] = 'Bar';
});
5 голосов
/ 12 ноября 2013

Используя ответ «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 );
    }
});
3 голосов
/ 12 сентября 2013

JQuery ...

<script>
   $(document).ajaxSuccess(
        function(event, xhr, settings){ 
          alert(xhr.responseText);
        }
   );
</script>
3 голосов
/ 08 декабря 2012

В дополнение к ответу meouw мне пришлось ввести код в iframe, который перехватывает вызовы XHR, и использовал приведенный выше ответ.Однако мне пришлось изменить

XMLHttpRequest.prototype.send = function(){

На:

XMLHttpRequest.prototype.send = function(arguments)

И мне пришлось изменить

oldSend.apply(this, arguments);

На:

oldSend.call(this, arguments);

Это было необходимо, чтобы заставить его работать в IE9 с режимом документа IE8 .Если это изменение не было выполнено, некоторые обратные вызовы, сгенерированные структурой компонентов (Visual WebGUI), не работали.Больше информации по этим ссылкам:

Без этих модификаций обратные передачи AJAX не прекращались.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...