Как перехватить все запросы AJAX, сделанные разными библиотеками JS

110

Я создаю веб-приложение с различными библиотеками JS (AngularJS, OpenLayers, ...), и мне нужен способ перехвата всех ответов AJAX, чтобы иметь возможность в случае истечения зарегистрированного сеанса пользователя (ответ возвращается со 401 Unauthorizedстатусом), чтобы перенаправить его на страницу входа.

Я знаю, что AngularJS предлагает interceptorsуправлять такими сценариями, но не смог найти способ добиться такой инъекции в запросы OpenLayers. Поэтому я выбрал ванильный подход JS.

Здесь я нашел этот фрагмент кода ...

(function(open) {

    XMLHttpRequest.prototype.open = function(method, url, async, user, pass) {

        this.addEventListener("readystatechange", function() {
            console.log(this.readyState); // this one I changed
        }, false);

        open.call(this, method, url, async, user, pass);
    };

})(XMLHttpRequest.prototype.open);

... который я адаптировал и выглядит так, как будто он ведет себя так, как ожидалось (тестировал его только в последнем Google Chrome).

Поскольку он изменяет прототип XMLHTTPRequest, мне интересно, насколько это может быть опасным или может привести к серьезным проблемам с производительностью. И, кстати, есть ли какая-нибудь действенная альтернатива?

Обновление: как перехватывать запросы до их отправки

Предыдущий трюк работает нормально. Но что, если в том же сценарии вы захотите ввести некоторые заголовки до отправки запроса? Сделайте следующее:

(function(send) {

    XMLHttpRequest.prototype.send = function(data) {

        // in this case I'm injecting an access token (eg. accessToken) in the request headers before it gets sent
        if(accessToken) this.setRequestHeader('x-access-token', accessToken);

        send.call(this, data);
    };

})(XMLHttpRequest.prototype.send);
Меттьюс
источник
4
Для меня это совершенно безопасно.
Barmar
Единственное влияние на производительность заключается в том, что он будет запускать дополнительную функцию во время каждого ответа AJAX, но это то, что вы хотите сделать.
Barmar
я искал что-то подобное. Большое спасибо
Silver Moon

Ответы:

36

Этот тип перехвата функций совершенно безопасен и регулярно выполняется для других методов по другим причинам.

И единственное влияние на производительность на самом деле - это только один дополнительный вызов функции для каждого .open()плюс любой код, который вы выполняете самостоятельно, что, вероятно, несущественно, когда задействован сетевой вызов.


В IE это не отловит код, который пытается использовать ActiveXObjectметод управления для выполнения Ajax. Хорошо написанный код сначала ищет XMLHttpRequestобъект и использует его, если он доступен, и который был доступен начиная с IE 7. Но может быть какой-то код, который использует этот ActiveXObjectметод, если он доступен, что было бы истинным в гораздо более поздних версиях IE.


В современных браузерах есть и другие способы выполнения вызовов Ajax, например fetch()интерфейс, поэтому, если кто-то хочет перехватить все вызовы Ajax, вам нужно перехватить больше, чем просто XMLHttpRequest.

jfriend00
источник
1
Привет, @ jfriend00 - как бы вы перехватили все запросы API на получение - stackoverflow.com/questions/44728723/… ?
colemerrick
1
@bagofcole - Вы, вероятно, могли бы исправить эту fetch()функцию, чтобы перехватить все вызовы к ней - хотя я никогда не пробовал этого сам. Похоже, этот модуль это делает.
jfriend00
Ломает ютуб при попытке перехватить comment_service_ajaxзапросы.
Leeroy
3

Это не будет перехватывать XMLHttpRequests для некоторых версий IE (9 и ниже) . В зависимости от библиотеки они могут сначала искать проприетарный элемент управления ActiveX IE.

И, конечно, все ставки отключены, если вы используете нестрогий DOCTYPE в IE, но я уверен, что вы это знали.

Ссылка: CanIuse

Джереми Дж. Старчер
источник
2

Как любезно отмечает редактор AMO Firefox Rob W,

Следующий код изменяет поведение XMLHttpRequest. По умолчанию, если третий («асинхронный») параметр не указан, по умолчанию он принимает значение true. Когда он указан и не определен, он эквивалентен «false», что превращает запрос в синхронный HTTP-запрос. Это приводит к блокировке пользовательского интерфейса во время обработки запроса, а также отключаются некоторые функции API XMLHttpRequest.

...

Чтобы исправить это, замените open.call (....) на open.apply (this, arguments);

А вот справочная ссылка:

https://xhr.spec.whatwg.org/#the-open()-method

Уолти Юнг
источник
(где «Следующий код» относится к отрывку из вопроса)
Роб В.