Cómo interceptar todas las solicitudes AJAX realizadas por diferentes bibliotecas JS

110

Estoy construyendo una aplicación web con diferentes bibliotecas JS (AngularJS, OpenLayers, ...) y necesito una forma de interceptar todas las respuestas AJAX para poder, en caso de que la sesión del usuario registrado expire (la respuesta vuelve con el 401 Unauthorizedestado), redirigirlo a la página de inicio de sesión.

Sé que AngularJS ofrece interceptorsadministrar tales escenarios, pero no pude encontrar una manera de lograr dicha inyección en las solicitudes de OpenLayers. Así que opté por un enfoque JS vainilla.

Aquí encontré este fragmento 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 adapté y parece que se comporta como se esperaba (solo lo probé en el último Google Chrome).

Como modifica el prototipo de XMLHTTPRequest, me pregunto qué tan peligroso podría resultar esto o si podría producir serios problemas de rendimiento. Y, por cierto, ¿habría alguna alternativa válida?

Actualización: cómo interceptar solicitudes antes de que se envíen

El truco anterior funciona bien. Pero, ¿qué pasa si en el mismo escenario desea inyectar algunos encabezados antes de que se envíe la solicitud? Haz lo siguiente:

(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
fuente
4
Me parece perfectamente seguro.
Barmar
El único impacto en el rendimiento es que ejecutará una función adicional durante cada respuesta AJAX, pero eso es lo que desea hacer.
Barmar
estaba buscando algo como esto. muchas gracias
Silver Moon

Respuestas:

36

Este tipo de función de enganche es perfectamente seguro y se realiza regularmente en otros métodos por otras razones.

Y, el único impacto en el rendimiento es realmente solo una llamada de función adicional por cada .open()más el código que ejecute usted mismo, lo que probablemente sea irrelevante cuando se trata de una llamada de red.


En IE, esto no detectará ningún código que intente usar el ActiveXObjectmétodo de control para hacer Ajax. El código bien escrito busca primero el XMLHttpRequestobjeto y lo usa si está disponible y ha estado disponible desde IE 7. Pero, podría haber algún código que use el ActiveXObjectmétodo si está disponible, lo que sería cierto en versiones mucho más recientes de IE.


En los navegadores modernos, hay otras formas de emitir llamadas Ajax, como la fetch()interfaz, por lo que si uno está buscando conectar todas las llamadas Ajax, debe conectar más que solo XMLHttpRequest.

jfriend00
fuente
1
Hola @ jfriend00: ¿cómo engancharías todas las solicitudes de fetch api - stackoverflow.com/questions/44728723/… ?
colemerrick
1
@bagofcole: presumiblemente, podría parchear la fetch()función para interceptar todas las llamadas a ella, aunque nunca lo he intentado. Parece que este módulo hace eso.
jfriend00
Rompe YouTube cuando intenta enganchar comment_service_ajaxsolicitudes.
Leeroy
3

Esto no detectará XMLHttpRequests para algunas versiones de IE (9 y anteriores) . Dependiendo de la biblioteca, pueden buscar primero el control ActiveX propietario de IE.

Y, por supuesto, todas las apuestas están canceladas si está utilizando un DOCTYPE no estricto en IE, pero estoy seguro de que lo sabía.

Referencia: CanIuse

Jeremy J Starcher
fuente
2

Como señaló amablemente el editor AMO de Firefox Rob W,

El siguiente código cambia el comportamiento de XMLHttpRequest. De forma predeterminada, si no se especifica el tercer parámetro ("async"), el valor predeterminado es verdadero. Cuando se especifica y no se define, es equivalente a "falso", que convierte una solicitud en una solicitud HTTP sincrónica. Esto hace que la interfaz de usuario se bloquee mientras se procesa la solicitud, y algunas funciones de la API XMLHttpRequest también están deshabilitadas.

...

Para arreglar esto, reemplace open.call (....) con open.apply (esto, argumentos);

Y aquí hay un enlace de referencia:

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

Walty Yeung
fuente
(donde "El siguiente código" se refiere al fragmento de la pregunta)
Rob W