jQuery ajax (jsonp) ignora un tiempo de espera y no activa el evento de error

Para agregar un manejo básico de errores, quería reescribir un fragmento de código que usaba $ .getJSON de jQuery para extraer algunas fotos de Flickr. La razón para hacer esto es que $ .getJSON no proporciona manejo de errores o trabaja con tiempos de espera.

Como $ .getJSON es solo una envoltura alrededor de $ .ajax, decidí reescribir la cosa y sorprender a la sorpresa, funciona a la perfección.

Ahora la diversión comienza sin embargo. Cuando provoco deliberadamente un 404 (al cambiar la URL) o hago que la red agote el tiempo de espera (al no estar conectado a las interwebs), el evento de error no se dispara, en absoluto. No sé qué estoy haciendo mal. La ayuda es muy apreciada.

Aquí está el código:

$(document).ready(function(){ // var jsonFeed = "http://api.flickr.com/services/feeds/photos_public.gne"; // correct URL var jsonFeed = "http://api.flickr.com/services/feeds/photos_public.gne_______"; // this should throw a 404 $.ajax({ url: jsonFeed, data: { "lang" : "en-us", "format" : "json", "tags" : "sunset" }, dataType: "jsonp", jsonp: "jsoncallback", timeout: 5000, success: function(data, status){ $.each(data.items, function(i,item){ $("").attr("src", (item.media.m).replace("_m.","_s.")) .attr("alt", item.title) .appendTo("ul#flickr") .wrap("
  • "); if (i == 9) return false; }); }, error: function(XHR, textStatus, errorThrown){ alert("ERREUR: " + textStatus); alert("ERREUR: " + errorThrown); } }); });

    Me gustaría agregar que se hizo esta pregunta cuando jQuery estaba en la versión 1.4.2

      jQuery 1.5 y superior tienen mejor soporte para el manejo de errores con solicitudes JSONP. Sin embargo, debe usar el método $.ajax lugar de $.getJSON . Para mí, esto funciona:

       var req = $.ajax({ url : url, dataType : "jsonp", timeout : 10000 }); req.success(function() { console.log('Yes! Success!'); }); req.error(function() { console.log('Oh noes!'); }); 

      El tiempo de espera parece ser el truco y llamar al controlador de errores, cuando no hay una solicitud exitosa después de 10 segundos.

      Hice un pequeño blogpost sobre este tema también.

      Esta es una limitación conocida con la implementación nativa de jsonp en jQuery. El siguiente texto es de IBM Developer Works

      JSONP es una técnica muy poderosa para crear mashups, pero, desafortunadamente, no es una panacea para todas sus necesidades de comunicación entre dominios. Tiene algunos inconvenientes que deben tenerse en cuenta antes de comprometer recursos de desarrollo. En primer lugar, no hay manejo de errores para las llamadas JSONP. Si la inserción del script dynamic funciona, se te llama; si no, no pasa nada. Simplemente falla silenciosamente. Por ejemplo, no puede detectar un error 404 del servidor. Tampoco puede cancelar o reiniciar la solicitud. Sin embargo, puede agotar el tiempo de espera después de esperar una cantidad razonable de tiempo. (Las futuras versiones de jQuery pueden tener una característica de cancelación para solicitudes JSONP).

      Sin embargo, hay un complemento jsonp disponible en GoogleCode que brinda soporte para el manejo de errores. Para comenzar, solo haga los siguientes cambios a su código.

      Puede descargarlo o simplemente agregar una referencia de script al complemento.

        

      Luego modifique su llamada ajax como se muestra a continuación:

       $(function(){ //var jsonFeed = "http://api.flickr.com/services/feeds/photos_public.gne"; // correct URL var jsonFeed = "http://api.flickr.com/services/feeds/photos_public.gne_______"; // this should throw a 404 $.jsonp({ url: jsonFeed, data: { "lang" : "en-us", "format" : "json", "tags" : "sunset" }, dataType: "jsonp", callbackParameter: "jsoncallback", timeout: 5000, success: function(data, status){ $.each(data.items, function(i,item){ $("").attr("src", (item.media.m).replace("_m.","_s.")) .attr("alt", item.title) .appendTo("ul#flickr") .wrap("
    • "); if (i == 9) return false; }); }, error: function(XHR, textStatus, errorThrown){ alert("ERREUR: " + textStatus); alert("ERREUR: " + errorThrown); } }); });

      Una solución si estás atrapado con jQuery 1.4:

       var timeout = 10000; var id = setTimeout( errorCallback, timeout ); $.ajax({ dataType: 'jsonp', success: function() { clearTimeout(id); ... } }); 

      Esta puede ser una limitación “conocida” de jQuery; sin embargo, no parece estar bien documentado. Pasé aproximadamente 4 horas hoy tratando de entender por qué mi tiempo de espera no funcionaba.

      Cambié a jquery.jsonp y funcionó como un encanto. Gracias.

      Parece ser resuelto a partir de jQuery 1.5. He intentado con el código anterior y obtengo la callback.

      Digo “parece ser” porque la documentación de la callback de error para jQuery.ajax () todavía tiene la siguiente nota:

      Nota: Este controlador no se llama para secuencias de comandos entre dominios y solicitudes JSONP.

      El complemento jquery-jsonp jQuery mencionado en la respuesta de José Basilio ahora se puede encontrar en GitHub .

      Lamentablemente, la documentación es un tanto espartana, así que proporcioné un ejemplo simple:

        $.jsonp({ cache: false, url: "url", callbackParameter: "callback", data: { "key" : "value" }, success: function (json, textStatus, xOptions) { // handle success - textStatus is "success" }, error: function (xOptions, textStatus) { // handle failure - textStatus is either "error" or "timeout" } }); 

      Importante: incluya el parámetro de callback en la llamada $ .jsonp (), de lo contrario, he encontrado que la función de callback nunca se inyecta en la cadena de consulta de la llamada de servicio (actual a partir de la versión 2.4.0 de jquery-jsonp).

      Sé que esta pregunta es antigua, pero el problema del manejo de errores usando JSONP aún no está ‘resuelto’. Esperemos que esta actualización ayude a otros ya que esta pregunta es la mejor clasificada dentro de Google para “manejo de errores jquery jsonp”.

      ¿Qué hay de escuchar el evento onerror del guión? Tuve este problema y lo resolví parcheando el método de jquery donde se creó la etiqueta del script. Aquí está el código de código interesante:

       // Attach handlers for all browsers script.onload = script.onreadystatechange = function( _, isAbort ) { if ( isAbort || !script.readyState || /loaded|complete/.test( script.readyState ) ) { cleanup(); // Callback if not abort if ( !isAbort ) { callback( 200, "success" ); } } }; /* ajax patch : */ script.onerror = function(){ cleanup(); // Sends an inappropriate error, still better than nothing callback(404, "not found"); }; function cleanup(){ // Handle memory leak in IE script.onload = script.onreadystatechange = null; // Remove the script if ( head && script.parentNode ) { head.removeChild( script ); } // Dereference the script script = undefined; } 

      ¿Qué piensas de esta solución? ¿Es probable que cause problemas de compatibilidad?