2010-08-29 36 views
65

Bien, básicamente quiero tener un poco de javascript en una página que de alguna manera adjunte algún tipo de oyente de eventos globales que pueda detectar y hacer algo si se realiza una solicitud ajax (sin llamar directamente desde el llamada), independientemente de cómo se realice la llamada ajax.JavaScript detectar un evento AJAX

Descubrí cómo hacer esto con jquery - si la solicitud de ajax se está haciendo por jquery. He aquí un ejemplo de código para esto:

$.post(
    // requested script 
    'someScript.php', 
    // data to send 
    { 
    'foo' : 'bar', 
    'a' : 'b' 
    }, 
    // receive response 
    function(response){ 
    // do something 
    } 
); // .post 

// global event listener  
$(document).ajaxSend(
    function(event,request,settings){ 
    alert(settings.url); // output: "someScript.php" 
    alert(settings.data); // output: "foo=bar&a=b" 
    } 
); 

Con este código, independientemente de dónde/cómo me llamo $ .post (..), el detector de eventos mundial se disparará. También funciona si uso $ .get o $ .ajax (cualquier método jquery ajax), independientemente de cómo/cuándo lo llamo (adjunto como un clic, en la carga de la página, lo que sea).

Sin embargo, deseo poder ampliar este detector para que se active independientemente de qué marco de js se utilice, o incluso si no se utiliza el marco. Así por ejemplo, si yo fuera a también incluir en una página el siguiente código (genérico código de ajax de w3schools):

function loadXMLDoc() 
{ 
if (window.XMLHttpRequest) 
    {// code for IE7+, Firefox, Chrome, Opera, Safari 
    xmlhttp=new XMLHttpRequest(); 
    } 
else 
    {// code for IE6, IE5 
    xmlhttp=new ActiveXObject("Microsoft.XMLHTTP"); 
    } 
xmlhttp.onreadystatechange=function() 
    { 
    if (xmlhttp.readyState==4 && xmlhttp.status==200) 
    { 
    document.getElementById("myDiv").innerHTML=xmlhttp.responseText; 
    } 
    } 
xmlhttp.open("GET","test.txt",true); 
xmlhttp.send(); 
} 

Y luego tengo en algún enlace al azar una llamada onclick a esa función, mi el oyente global de eventos ajax debería poder también detectar esta solicitud. Bueno, agregué ese código a mi página y lo adjunté al clic en un enlace aleatorio (sí, el código en sí funciona), pero el código "detector de eventos globales" de jquery anterior no detectó esa llamada.

Hice algo más de excavación y sé que básicamente puedo guardar el objeto en un objeto temporal y sobrescribir el objeto actual con un objeto "envoltorio" que llamará a una función específica y luego llamará a la función temporal, pero esto me requiere saber de antemano el objeto original que se está creando/usando. Pero no siempre sabré eso antes de tiempo ...

Entonces ... ¿es esto posible? ¿Hay alguna manera de detectar que se haya realizado una solicitud de ajax get/post, independientemente de si se realizó con un objeto genérico o desde xyz framework? ¿O voy a tener que hacer un código duplicado para manejar cada marco y también saber de antemano los objetos ajax que se están creando/usando?

edición:

me olvidó mencionar que no es suficiente para detectar que una petición se produjo. También necesito capturar los datos que se envían en la solicitud. El enlace proporcionado en los comentarios a continuación ayudará a determinar si se realizó una solicitud "a", pero no a enviar los datos. PD. - La respuesta proporcionada en el siguiente enlace no es muy clara, al menos para mí de todos modos.

+4

posible duplicado de [ Averiguar cuándo se realizó una solicitud XMLHttpRequest sin devoluciones de llamada] (http://stackoverflow.com/questions/2255248/figuring-out-when-a-xmlhttprequest-request-was-made-without-callbacks) –

+0

¡Gracias por el enlace! Esta pregunta no es del todo así, porque también necesitaba poder capturar los datos que se envían en la solicitud (que supongo que no incluí ni edité). Sin embargo, ME HIZO ponerme en el camino correcto y creo que encontré una solución, que se publicará cuando la prueba esté completa. ¡Gracias! –

+0

Creo que lo que está buscando es en esta cuestión sobre la manipulación del prototipo, pero de una mejor manera https://stackoverflow.com/q/20689481/3462483 – doz87

Respuesta

99

bien esto es lo que he encontrado hasta el momento:

<script type='text/javascript'> 
var s_ajaxListener = new Object(); 
s_ajaxListener.tempOpen = XMLHttpRequest.prototype.open; 
s_ajaxListener.tempSend = XMLHttpRequest.prototype.send; 
s_ajaxListener.callback = function() { 
    // this.method :the ajax method used 
    // this.url :the url of the requested script (including query string, if any) (urlencoded) 
    // this.data :the data sent, if any ex: foo=bar&a=b (urlencoded) 
} 

XMLHttpRequest.prototype.open = function(a,b) { 
    if (!a) var a=''; 
    if (!b) var b=''; 
    s_ajaxListener.tempOpen.apply(this, arguments); 
    s_ajaxListener.method = a; 
    s_ajaxListener.url = b; 
    if (a.toLowerCase() == 'get') { 
    s_ajaxListener.data = b.split('?'); 
    s_ajaxListener.data = s_ajaxListener.data[1]; 
    } 
} 

XMLHttpRequest.prototype.send = function(a,b) { 
    if (!a) var a=''; 
    if (!b) var b=''; 
    s_ajaxListener.tempSend.apply(this, arguments); 
    if(s_ajaxListener.method.toLowerCase() == 'post')s_ajaxListener.data = a; 
    s_ajaxListener.callback(); 
} 
</script> 

INSTRUCCIONES:

Sólo c/p este en su página o incluirlo en un archivo .js o lo que sea. Esto creará un objeto llamado s_ajaxListener. Siempre que un AJAX solicitud GET o POST se hizo, s_ajaxListener.callback() se llama, y ​​las siguientes propiedades están disponibles:

s_ajaxListener.method: El método ajax utilizado. Esto debe ser GET o POST. NOTA: el valor puede no siempre estar en mayúscula, depende de cómo se codificó la solicitud específica.Estoy debatiendo sobre la conveniencia de incluirlo automáticamente en mayúsculas o de dejarlo en otra cosa a LowCase() para una comparación insensible a mayúsculas y minúsculas.

s_ajaxListener.url: La url del script solicitado (incluida la cadena de consulta, si la hay) (urlencoded). Me he dado cuenta, dependiendo de cómo se envían los datos y desde qué navegador/marco, por ejemplo, este valor podría terminar siendo "" o "+" o "% 20". Estoy debatiendo la sabiduría de decodificarlo aquí o dejárselo a otra cosa.

s_ajaxListener.data: los datos enviados, si cualquier ex: foo = bar & a = b (el mismo 'problema' como .url con él que es codificada en URL)

NOTAS:

Tal como está, esto no es compatible con IE6. esta solución no es lo suficientemente buena para mí, ya que quiero que sea compatible con IE6. Pero dado que muchas otras personas no se preocupan por IE6, decidí publicar mi solución en su estado actual, ya que debería funcionar para usted si no le importa IE6.

He probado esto en (a partir de esta fecha publicada): Safari actual, Chrome actual, FireFox actual, IE8, IE8 (compatible con IE7). Actualmente no funciona con IE6 porque IE6 usa un objeto ActiveX, mientras que prácticamente todo lo demás usa XMLHttpRequest.

En este momento no tengo ni idea de cómo, básicamente, prototipar/extender/sobrecargar (?) ActiveXObject ("Microsoft.XMLHTTP"). Esto es lo que estoy investigando ... ¿Alguien sabe de primera mano?

Debajo de cada uno de los navegadores que probé anteriormente, esto funciona con las solicitudes AJAX de un objeto genérico, y también de los frameworks de jquery y prototype. Sé que hay otros marcos por ahí, pero IMO estos 2 son los principales. Posiblemente podría QA MooTools, pero aparte de eso, estoy bien con solo probarlos.

Si alguien quiere contribuir de prueba y la publicación de resultados sobre otros navegadores y/o marcos, sería apreciado :)

+1

Puede definir una función de envoltura para IE6, como [Sarissa] (http : //dev.abiss.gr/sarissa/) does; eche un vistazo a [Reinventar XMLHttpRequest] (http://www.ilinsky.com/articles/XMLHttpRequest/) para ver cómo se puede hacer esto (no tengo tiempo ahora). Usted [no puede extender] (http://stackoverflow.com/questions/594428/how-can-i-add-properties-to-an-object-in-ie6/594460#594460) un objeto ActiveX, pero usted puede extender su propia función de envoltura que simplemente emula las propiedades necesarias. Creo que la mayoría de las bibliotecas prueban la presencia de 'window.XMLHttpRequest' y se detectará su objeto contenedor. –

+0

También tenga en cuenta que IE8 en IE7 modo de compatibilidad ≠ IE7.Sospecho que el objeto 'XMLHttpRequest' es una de las cosas que difieren: en IE7 parece ser simplemente una función de envoltura sobre un componente ActiveX, mientras que en IE8 se puede implementar como un objeto XHR 'real'. –

+1

Actualmente no funciona en Firefox. Error XMLHttpRequest.open.apply – HMR

5

para IE 6 compatibilidad, ¿qué tal:

<script type='text/javascript'> 
    var s_ajaxListener = new Object(); 

    // Added for IE support 
    if (typeof XMLHttpRequest === "undefined") { 
    XMLHttpRequest = function() { 
     try { return new ActiveXObject("Msxml2.XMLHTTP.6.0"); } 
     catch (e) {} 
     try { return new ActiveXObject("Msxml2.XMLHTTP.3.0"); } 
     catch (e) {} 
     try { return new ActiveXObject("Microsoft.XMLHTTP"); } 
     catch (e) {} 
     throw new Error("This browser does not support XMLHttpRequest."); 
    }; 
    } 

    s_ajaxListener.tempOpen = XMLHttpRequest.prototype.open; 
    s_ajaxListener.tempSend = XMLHttpRequest.prototype.send; 
    s_ajaxListener.callback = function() { 
    // this.method :the ajax method used 
    // this.url :the url of the requested script (including query string, if any) (urlencoded) 
    // this.data :the data sent, if any ex: foo=bar&a=b (urlencoded) 
    } 

    XMLHttpRequest.prototype.open = function(a,b) { 
    if (!a) var a=''; 
    if (!b) var b=''; 
    s_ajaxListener.tempOpen.apply(this, arguments); 
    s_ajaxListener.method = a; 
    s_ajaxListener.url = b; 
    if (a.toLowerCase() == 'get') { 
     s_ajaxListener.data = b.split('?'); 
     s_ajaxListener.data = s_ajaxListener.data[1]; 
    } 
    } 

    XMLHttpRequest.prototype.send = function(a,b) { 
    if (!a) var a=''; 
    if (!b) var b=''; 
    s_ajaxListener.tempSend.apply(this, arguments); 
    if(s_ajaxListener.method.toLowerCase() == 'post')s_ajaxListener.data = a; 
    s_ajaxListener.callback(); 
    } 
</script> 
+5

sí, eso es más o menos lo que hice en ese momento ... pero IE6 es algo que nadie debería soportar más, especialmente desde que Microsoft dejó de apoyarlo (por extensión, no era compatible con XP) a partir de abril de 2014 –

Cuestiones relacionadas