Como interceptar todas as solicitações AJAX feitas por diferentes bibliotecas JS

110

Estou construindo um aplicativo da web com diferentes bibliotecas JS (AngularJS, OpenLayers, ...) e preciso de uma forma de interceptar todas as respostas AJAX para poder, no caso de a sessão do usuário logado expirar (a resposta volta com 401 Unauthorizedstatus), redirecioná-lo para a página de login.

Eu sei que o AngularJS se oferece interceptorspara gerenciar esses cenários, mas não foi capaz de encontrar uma maneira de conseguir tal injeção nas solicitações do OpenLayers. Então, optei por uma abordagem JS baunilha.

Aqui encontrei este pedaço de código ...

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

... que adaptei e parece que se comporta como esperado (testei apenas no último Google Chrome).

Como ele modifica o protótipo de XMLHTTPRequest, estou me perguntando o quão perigoso isso pode resultar ou se pode produzir sérios problemas de desempenho. E a propósito, haveria alguma alternativa válida?

Atualização: como interceptar solicitações antes de serem enviadas

O truque anterior funciona bem. Mas e se no mesmo cenário você quiser injetar alguns cabeçalhos antes que a solicitação seja enviada? Faça o seguinte:

(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);
mettjus
fonte
4
Parece perfeitamente seguro para mim.
Barmar de
O único impacto no desempenho é que ele executará uma função extra durante cada resposta AJAX, mas é isso que você deseja fazer.
Barmar de
Eu estava procurando por algo parecido com isto. muito obrigado
Silver Moon de

Respostas:

36

Este tipo de gancho de função é perfeitamente seguro e é feito regularmente em outros métodos por outros motivos.

E o único impacto no desempenho é realmente apenas uma chamada de função extra para cada um, .open()mais qualquer código que você mesmo execute, o que provavelmente é irrelevante quando uma chamada de rede está envolvida.


No IE, isso não detectará nenhum código que tente usar o ActiveXObjectmétodo de controle de fazer Ajax. Um código bem escrito procura primeiro pelo XMLHttpRequestobjeto e o usa, se disponível, e está disponível desde o IE 7. Mas, pode haver algum código que usa o ActiveXObjectmétodo se estiver disponível, o que seria verdadeiro em versões muito posteriores do IE.


Em navegadores modernos, existem outras maneiras de emitir chamadas Ajax, como a fetch()interface, portanto, se alguém estiver procurando conectar todas as chamadas Ajax, será necessário conectar mais do que apenas XMLHttpRequest.

jfriend00
fonte
1
Olá @ jfriend00 - como você conectaria todas as solicitações de API de busca - stackoverflow.com/questions/44728723/… ?
colemerrick
1
@bagofcole - Você poderia provavelmente fazer um monkey-patch na fetch()função para interceptar todas as chamadas para ela - embora eu nunca tenha tentado isso. Parece que este módulo faz isso.
jfriend00
Interrompe o YouTube ao tentar obter comment_service_ajaxsolicitações.
Leeroy
3

Isso não capturará XMLHttpRequests para algumas versões do IE (9 e abaixo) . Dependendo da biblioteca, eles podem procurar o controle ActiveX proprietário do IE primeiro.

E, claro, todas as apostas estão canceladas se você estiver usando um DOCTYPE não estrito no IE, mas tenho certeza que você sabia disso.

Referência: CanIuse

Jeremy J Starcher
fonte
2

Como gentilmente apontado pelo Firefox AMO Editor Rob W,

O código a seguir altera o comportamento de XMLHttpRequest. Por padrão, se o terceiro parâmetro ("async") não for especificado, o padrão é verdadeiro. Quando é especificado e indefinido, é equivalente a "false", que transforma uma solicitação em uma solicitação HTTP síncrona. Isso faz com que a IU seja bloqueada enquanto a solicitação está sendo processada e alguns recursos da API XMLHttpRequest também são desativados.

...

Para corrigir isso, substitua open.call (....) por open.apply (this, argumentos);

E aqui está um link de referência:

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

Walty Yeung
fonte
(onde "O código a seguir" se refere ao snippet da pergunta)
Rob W