JavaScript / jQuery: ¿Cómo asegurarse de que el evento de seguimiento de clics entre dominios tenga éxito antes de que el usuario abandone la página?

Estoy implementando el seguimiento de clics desde varias páginas en nuestra intranet corporativa para agregar algunas de las funciones de enlace populares de gran demanda (“enlaces más populares en su departamento en las últimas 24 horas”, etc.)

Estoy usando .live () de jQuery para enlazar con el evento mousedown para todos los elementos de enlace en la página, filtrar el evento y luego desencadenar una solicitud de pseudo-ajax con varios datos a un servidor back-end antes de devolver la verdad para que la acción de enlace se dispara:

$("#contentarea a").live("mousedown", function(ev) { // // detect event, find closest link, process it here // $.ajax({ url: 'my-url', cache: false, dataType: 'jsonp', jsonp: 'cb', data: myDataString, success: function() { // silence is golden -- server does send success JSONP but // regardless of success or failure, we allow the user to continue } }); return true; // allow event to continue, user leaves the page. } 

Como probablemente pueda adivinar de lo anterior, tengo varias restricciones:

  • El servidor de seguimiento de back-end está en un subdominio diferente de la página de llamada. No puedo resolver esto. Es por eso que estoy usando JSONP (y GET) en lugar de AJAX adecuado con POST. No puedo implementar un proxy AJAX ya que los servidores web no tienen acceso de red saliente para los scripts.
  • Probablemente esto no sea relevante, pero en interés de la divulgación completa, el contenido y la secuencia de comandos se encuentran dentro de un iframe de “contenido principal” (y esto no va a cambiar. Probablemente moveré al oyente del evento al marco principal para monitorearlo). enlaces y todo el contenido secundario, pero el paso 1 hace que funcione correctamente en el caso simplificado de “1 ventana secundaria”). Padre e hijo son el mismo dominio.
  • El back-end es IIS / ASP (de nuevo, una restricción, ¡no preguntes!), Así que no puedo dividir inmediatamente el proceso de back-end o terminar la respuesta, pero seguir procesando como podría hacerlo en una plataforma mejor

A pesar de todo esto, en su mayor parte, el sistema funciona: hago clic en los enlaces de la página y aparecen en la base de datos casi a la perfección.

Sin embargo, no es confiable: para una gran cantidad de enlaces, especialmente los enlaces externos que tienen su objective establecido en “_top”, no aparecen. Si el enlace se abre en una nueva pestaña o ventana, se registra correctamente.

He descartado errores de script, parece que:

(a) la solicitud nunca llega al back-end a tiempo; o

(b) la solicitud lo está haciendo, pero ASP está detectando que el cliente se está desconectando poco después, y como se trata de una solicitud GET, no la está procesando.

Sospecho (b), ya que la latencia del servidor es muy rápida y muchos enlaces se registran en Aceptar. Si pongo una ventana emergente de alerta después de que se active el evento, o establezca el valor de retorno en falso, el clic se registra en Aceptar.

¿Algún consejo sobre cómo puedo resolver esto (en el contexto de que no puedo cambiar mis restricciones)? No puedo hacer que la solicitud GET sea sincrónica ya que no es verdadero AJAX.

P : ¿Funcionaría mejor si estuviera realizando una solicitud POST a ASP? Si (b) es el culpable, ¿se comportaría de manera diferente para POST vs GET? Si es así, podría usar un iframe / formulario oculto para POSTAR los datos. sin embargo, sospecho que esto sería más lento y torpe, y aún podría no llegar a tiempo. No podría escuchar para ver si la solicitud se completa porque es de dominio cruzado.

P : ¿Puedo agregar un retraso al script una vez que se haya activado la solicitud GET? ¿Cómo hago esto de una manera de un solo hilo? Necesito devolver true desde mi función para garantizar que el evento predeterminado se active, por lo que no puedo usar setTimeout (). ¿Un bucle cerrado en espera de “éxito” para disparar y establecer un trabajo variable? Me preocupa que esto congelaría las cosas demasiado y la respuesta se ralentizaría. Supongo que el complemento jQuery delay () es solo un bucle también.

¿O es algo más que no he pensado que sea el culpable?

No necesito confiabilidad a prueba de balas. Si todos los enlaces son igualmente susceptibles al 95% del tiempo, está bien. Sin embargo, en este momento, algunos enlaces se pueden capturar el 100% del tiempo, mientras que otros son inalcanzables, lo que no va a cortar por lo que quiero lograr.

Gracias por adelantado.

Intentaría devolver falso desde el controlador de eventos de enlace, recordar la URL y navegar solo cuando la solicitud JSONP tenga éxito. Ojalá no agregue demasiada latencia. Teniendo en cuenta que está en la inranet, podría estar bien.

Yo intentaría un enfoque diferente. Puedes enlazar a un evento diferente como:

 $(window).unload(function(event) { // tracking code here }); 

Resuelto

La respuesta corta es: no hay una forma confiable de hacer este dominio cruzado con una solicitud GET. Intenté todo tipo de cosas, incluso almacenar el evento e intentar reproducirlo más tarde, y todo tipo de trucos para que funcionara.

Luego probé los bucles ajustados, y tampoco eran confiables.

Finalmente, acabo de ceder y utilicé una forma creada dinámicamente en la que se publicaron los resultados, con el objective establecido en un iFrame oculto.

Eso funciona de manera confiable: parece que el navegador se detiene para finalizar su solicitud POST antes de continuar, y ASP respeta la POST. Resulta que no es ‘torpe’ en absoluto. Claro, debido al modelo de seguridad del navegador no puedo ver el resultado … pero no importa en este caso.

Ahora me estoy pateando que no probé esa opción primero.