2011-03-05 14 views
77

Me gustaría saber si es posible "enganchar" en cada solicitud AJAX (ya sea a punto de ser enviado o en eventos) y realizar una acción . En este punto, supongo que hay otros scripts de terceros en la página. Algunos de estos pueden usar jQuery, mientras que otros no. es posible?Agregue un "gancho" a todas las solicitudes AJAX en una página

+0

Es posible con jQuery, por lo que es posible con el viejo Javascript simple, pero que tendría que tener por lo menos 2 "ganchos" para cada uno de ellos. De todos modos, ¿por qué usar ambos en la misma página? – yoda

+2

¿Qué le parece usar esta biblioteca? https://github.com/slorber/ajax-interceptor –

+0

Esta es una buena solución: http://stackoverflow.com/questions/25335648/how-to-intercept-all-ajax-requests-made-by-different- js-libraries – phazei

Respuesta

89

Inspirado por aviv's answer, investigué un poco y esto es lo que se me ocurrió.
No estoy seguro de que sea tan útil según los comentarios en el script y, por supuesto, solo funcionará para navegadores que usen un objeto nativo XMLHttpRequest.
Creo que funcionará si las bibliotecas de JavaScript están en uso, ya que usarán el objeto nativo si es posible.

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

Creativo. Los trucos de JS salvaron el día una vez más. –

+0

sería bueno ampliar esta respuesta para admitir los enganches posteriores a la solicitud –

+1

Basado en su implementación, ¡he publicado algo en NPM que funciona tanto con solicitudes como con respuestas! https: // github.com/slorber/ajax-interceptor –

9

Hay un truco para hacerlo.

Antes de ejecutar todos los scripts, tome el objeto original XHMHttpReuqest y guárdelo en una var diferente. A continuación, anule la XMLHttpRequest original y dirija todas las llamadas a través de su propio objeto.

Psuedo código:

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

Esta respuesta no es del todo correcta, si cambia el prototipo de un objeto, incluso el guardado será cambiado. Además, el prototipo completo se reemplaza con una función que romperá todas las solicitudes de Ajax. Sin embargo, me inspiró a ofrecer una respuesta. – meouw

19

Ya que mencionas jQuery, sé jQuery ofrece un método .ajaxSetup() que establece opciones ajax globales que incluyen el evento desencadena como success, error, y beforeSend - que es lo que suena como lo Estás buscando.

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

por supuesto que se necesita para verificar la disponibilidad de jQuery en cualquier página intenta utilizar esta solución sucesivamente.

+1

Gracias por la sugerencia, pero lamentablemente esto no intercepta las llamadas AJAX que no se realizan con AJAX. – Yuliy

+44

... lea su comentario .... – jondavidjohn

+5

En las noticias de hoy: Unicornios asesinados por llamadas AJAX que no están usando AJAX – Dashu

3

Además de de meouw respuesta, tuvo que inyectar código en un marco flotante que intercepta llamadas XHR, y se utiliza la respuesta anterior. Sin embargo, he tenido que cambiar

XMLHttpRequest.prototype.send = function(){ 

Para:

XMLHttpRequest.prototype.send = function(arguments) 

Y tuve que cambiar

oldSend.apply(this, arguments); 

Para:

oldSend.call(this, arguments); 

Esto era necesario para que funcione en IE9 con IE8 documento m oda. Si no se realizó esta modificación, algunos call-backs generados por el marco de componentes (Visual WebGUI) no funcionaron. Más información en estos enlaces:

Sin estas modificaciones devoluciones de datos AJAX no terminan.

3

jquery ...

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

jQuery no captará las solicitudes realizadas utilizando otras bibliotecas. Por ejemplo ExtJS. Si solo está utilizando jQuery, es una buena respuesta. De lo contrario, no funcionará todo el tiempo. – npiani

+0

ni siquiera captará las solicitudes de jquery si la instancia de jquery es diferente. Cambio en protype si es necesario –

4

Usando la respuesta de "meouw" Es mejor utilizar la siguiente solución si desea ver los resultados de la solicitud

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

Si usted no tiene que soportar < = IE8 que puede hacer esto que interceptará genéricamente cualquier AJAX a nivel mundial y no estropeará las devoluciones de llamadas, etc. que tal vez hayan sido asignadas por bibliotecas de terceros de AJAX. La respuesta aceptada no produce la respuesta real porque se llama demasiado pronto.

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

Algunos documentos más de lo que puede hacer aquí con la API de addEventListener aquí:

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

+0

¡Gracias! Eso funciona a la perfección. Solo modifico un poco: 'this.status' devuelve el estado del servidor en este caso' 200' si la solicitud es correcta, 404 si el elemento no se encontró, 500, etc. Admite el código, funciona perfectamente. – MrMins

+0

Esto puede sentirse viejo pero mereces todo el amor por esto. Estaba profundamente atrapado. Gracias un montón. –

+0

Simplemente porque he buscado un poco para esto. El evento '" load "' solo se ejecuta en caso de éxito. Si no le importa el resultado (solo que la consulta finalizó) puede usar el evento '" loadend '' –

4

he encontrado una buena biblioteca en Github que hace bien el trabajo, usted tiene que incluir antes de cualquier otro archivo js

https://github.com/jpillora/xhook

aquí es un ejemplo que añade una cabecera HTTP a cualquier incom ing respuesta

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

¡Excelente! ¡Pero no funcionó en la aplicación Cordova, incluso con un último complemento crosswalk web-view de crosswalk! –

+0

Esto funcionó perfectamente para mis necesidades particulares: en Wordpress, filtrado de eventos desde el plugin de Events Organizer calendario completo –

0

Ajax-hook es un lib de código abierto para enganchar objeto XMLHttpRequest global y cambiar la petición Ajax por defecto y la respuesta. GitHub: https://github.com/wendux/Ajax-hook, por ejemplo:

hookAjax({ 

    //hook callbacks 
    onreadystatechange:function(xhr){ 
    console.log("onreadystatechange called: %O",xhr) 
    }, 

    onload:function(xhr){ 
    console.log("onload called: %O",xhr) 
    }, 

    //hook function 
    open:function(arg,xhr){ 
    console.log("open called: method:%s,url:%s,async:%s",arg[0],arg[1],arg[2]) 
    } 

}) 
Cuestiones relacionadas