Додайте "гачок" до всіх запитів AJAX на сторінці


103

Мені хотілося б знати, чи можна "підключити" кожен запит AJAX (або як він збирається відправити, або на події) та виконати дію. На даний момент я припускаю, що на сторінці є й інші сторонні сценарії. Деякі з них можуть використовувати jQuery, а інші -. Чи можливо це?


Це можливо з jQuery, так що це можливо із звичайним старим JavaScript, але вам потрібно мати принаймні 2 "гачки" для кожного з них. У будь-якому випадку, навіщо використовувати обидва на одній сторінці?
йода

2
Як щодо використання цієї бібліотеки? github.com/slorber/ajax-interceptor
Себастьян Лорбер

Це хороше рішення: stackoverflow.com/questions/25335648 / ...
phazei

2
Примітка. Відповіді на це запитання не охоплюють дзвінки Ajax, здійснені за допомогою нової fetch()API тепер у сучасних браузерах.
jfriend00

Відповіді:


109

Надихнувшись відповіді Авіва , я трохи розслідував, і ось що я придумав.
Я не впевнений, що це все так корисно, як за коментарями до сценарію, і, звичайно, буде працювати лише для браузерів, що використовують нативний об’єкт 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
});

було б непогано поширити цю відповідь на підтримку гаків після запиту
Sebastien Lorber,

1
На основі вашої реалізації я опублікував щось на NPM, що працює як із запитами, так і з відповідями! github.com/slorber/ajax-interceptor
Себастьян Лорбер

4
console.log (xhr.responseText) - порожній рядок, оскільки в цей момент xhr порожній. якщо ви передасте змінну xhr до глобальної змінної та встановите затримку на кілька секунд, ви зможете отримати доступ до властивостей безпосередньо
Toolkit

5
приємна відповідь. Якщо ви хочете отримати дані відповіді, перевірте стан готовності та стан, коли стан змінився. xhr.onreadystatechange = function () {if (xhr.readyState == 4 && xhr.status == 200) {console.log (JSON.parse (xhr.responseText)); }}
Стенлі Ван

1
@ucheng Якщо ми додамо onreadystatechange xhr, чи замінить оригінальний метод зміни стану готового кращого використання xhrObj.addEventListener ("load", fn)
Мохамед Хуссейн

126

ПРИМІТКА. Прийнята відповідь не дає фактичної відповіді, оскільки її називають занадто рано.

Ви можете зробити це, що загалом перехопить будь-який 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)


Дякую! Це працює чудово. Я лише трохи змінюю: this.statusповерніть статус сервера в цьому випадку, 200якщо запит буде в порядку, 404, якщо елемент не знайдено, 500 і т.д.
MrMins

1
Це може здатися вам старим, але ви заслужили на це всю любов. Я глибоко застряг. Дякую купу.
Carles Alcolea

Просто тому, що я трохи шукав цього. "load"Подія викликається тільки на успіх. Якщо ви не переймаєтесь результатом (тільки щоб запит закінчився), ви можете скористатись "loadend"подією
Romuald Brunet

Щоб знайти це, минуло багато днів. Дякую за цей геніальний шматок.
Девід

Я спробував багато відповідей, і це прекрасно працює з WKWebView. У мене виникли проблеми з використанням подій Ajax, оскільки jQuery може не завантажуватися до того, як я дзвоню оценку JavaScript або використовувати addUserScript Дякую!
Джейк Ченг

21

Так як ви говорите JQuery, я знаю , що Jquery пропонує великий .ajaxSetup()метод , який встановлює глобальні параметри Ajax , які включають тригери подій , як success, errorі beforeSend- що то , що звучить як то , що ви шукаєте.

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

звичайно, вам потрібно буде перевірити наявність jQuery на будь-якій сторінці, на якій ви намагаєтесь використовувати це рішення.


1
Дякуємо за пропозицію, але це, на жаль, не перехоплює дзвінки AJAX, які виконуються без використання AJAX.
Юлій

8
У сьогоднішніх новинах: Єдинороги, вбиті дзвінками AJAX, які виконуються не за допомогою AJAX
Дашу

3
він не означає jquery AJAX об'єкт. Але навіть тоді ви
будете

1
Дуже корисно. Хотіли додати, ще одним тригером є statusCode. Підключивши щось на зразок statusCode: {403: function () {error msg} ви можете надати глобальну перевірку auth / perms / role для всіх функцій ajax без необхідності повторного запису жодного запиту .ajax.
Водяний кайман

8

Для цього є хитрість.

Перш ніж всі сценарії запущені, візьміть оригінальний об’єкт XHMHttpReuqest і збережіть його в іншому var. Потім замініть оригінальний XMLHttpRequest і направляйте всі дзвінки на нього через власний об’єкт.

Код Псуедо:

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

10
Ця відповідь не зовсім правильна, якщо змінити прототип об'єкта, навіть збережений буде змінено. Також весь прототип замінюється однією функцією, яка порушить всі запити на ajax. Це все ж надихало мене запропонувати відповідь.
meouw

8

Я знайшов хорошу бібліотеку в Github, яка добре виконує цю роботу, ви повинні включити її до будь-яких інших js-файлів

https://github.com/jpillora/xhook

ось приклад, який додає заголовка http до будь-якої вхідної відповіді

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

2
Чудовий! Але не працювало над додатком Кордова навіть із останнім хромованим плагіном для веб-перегляду на кросс-хові!
Іслам Атрашш

1
Це спрацювало ідеально для моїх потреб: У Wordpress фільтрування подій з повного календаря плагіна для Організатора подій
Альфредо Йонг

Працює не для всіх запитів, якийсь збір і xhr добре, але, наприклад, він не ловить xhr з google recaptcha
Sergio Quintero

@SergioQuintero: Я припускаю, що це ваша проблема GitHub: github.com/jpillora/xhook/isissue/102 . Спробуйте видалити тут свій коментар, оскільки це не було проблемою з бібліотекою.
тридцятиріччя

@SergioQuintero Будь-яке переопрацювання XHR-інтерфейсів відбувається лише в тому документі, а не в усьому світі в браузері, оскільки це було б великою діркою безпеки / конфіденційності. reCAPTCHA запускається в iframe, і ви не можете запустити заміщення там.
Walf

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

3

jquery ...

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

1
jQuery не буде вловлювати запити, зроблені за допомогою інших бібліотек. Наприклад, ExtJS. Якщо ви використовуєте лише jQuery, це хороша відповідь. Інакше він не працюватиме весь час.
npiani

1
він навіть не вловлює запити jquery, якщо екземпляр jquery інший. Зміна в прототипі за потреби
Шишир Арора

3

На додаток до відповіді meouw, мені довелося ввести код у iframe, який перехоплює виклики XHR, і використав вищевказану відповідь. Однак мені довелося змінити

XMLHttpRequest.prototype.send = function(){

До:

XMLHttpRequest.prototype.send = function(body)

І мені довелося змінити

oldSend.apply(this, arguments);

До:

oldSend.call(this, body);

Це було необхідно, щоб він працював в IE9 в режимі документа IE8 . Якщо ця модифікація не була здійснена, деякі зворотні дзвінки, створені компонентною рамкою (Visual WebGUI), не працювали. Більше інформації за цими посиланнями:

Без цих модифікацій передплати AJAX не припинялися.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.