Pour ajouter une gestion de base des erreurs, je voulais réécrire un morceau de code qui utilisait $ .getJSON de jQuery pour extraire certaines photos de Flickr. La raison pour cela est que $ .getJSON ne fournit pas de gestion des erreurs ou ne fonctionne pas avec des délais d'attente.
Étant donné que $ .getJSON n'est qu'un wrapper autour de $ .ajax, j'ai décidé de réécrire la chose et de surprendre la surprise, cela fonctionne parfaitement.
Maintenant, le plaisir commence. Lorsque je cause délibérément un 404 (en changeant l'URL) ou que le réseau expire (en n'étant pas connecté aux interwebs), l'événement d'erreur ne se déclenche pas du tout. Je ne sais pas ce que je fais mal. L'aide est très appréciée.
Voici le code:
$(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){
$("<img>").attr("src", (item.media.m).replace("_m.","_s."))
.attr("alt", item.title)
.appendTo("ul#flickr")
.wrap("<li><a href=\"" + item.link + "\"></a></li>");
if (i == 9) return false;
});
},
error: function(XHR, textStatus, errorThrown){
alert("ERREUR: " + textStatus);
alert("ERREUR: " + errorThrown);
}
});
});
Je voudrais ajouter que cette question a été posée lorsque jQuery était à la version 1.4.2
jQuery 1.5 et supérieur ont un meilleur support pour la gestion des erreurs avec les requêtes JSONP. Cependant, vous devez utiliser le $.ajax
méthode au lieu de $.getJSON
. Pour moi, cela fonctionne:
var req = $.ajax({
url : url,
dataType : "jsonp",
timeout : 10000
});
req.success(function() {
console.log('Yes! Success!');
});
req.error(function() {
console.log('Oh noes!');
});
Le délai d'attente semble faire l'affaire et appeler le gestionnaire d'erreurs, lorsqu'il n'y a pas de demande réussie après 10 secondes.
J'ai également fait un peu blogpost sur ce sujet.
Il s'agit d'une limitation connue avec l'implémentation jsonp native dans jQuery. Le texte ci-dessous provient de IBM DeveloperWorks
JSONP est une technique très puissante pour créer des mashups, mais, malheureusement, ce n'est pas un remède universel pour tous vos besoins de communication inter-domaines. Elle présente certains inconvénients qui doivent être sérieusement pris en compte avant d'engager des ressources de développement. Tout d'abord, il n'y a pas de gestion des erreurs pour les appels JSONP. Si l'insertion de script dynamique fonctionne, vous êtes appelé; sinon, rien ne se passe. Il échoue silencieusement. Par exemple, vous n'êtes pas en mesure de détecter une erreur 404 sur le serveur. Vous ne pouvez pas non plus annuler ou redémarrer la demande. Vous pouvez toutefois expirer après avoir attendu un temps raisonnable. (Les futures versions de jQuery peuvent avoir une fonction d'abandon pour les requêtes JSONP.)
Cependant, il existe un plug-in jsonp disponible sur GoogleCode qui prend en charge la gestion des erreurs. Pour commencer, apportez simplement les modifications suivantes à votre code.
Vous pouvez le télécharger ou simplement ajouter une référence de script au plug-in.
<script type="text/javascript"
src="http://jquery-jsonp.googlecode.com/files/jquery.jsonp-1.0.4.min.js">
</script>
Modifiez ensuite votre appel ajax comme indiqué ci-dessous:
$(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){
$("<img>").attr("src", (item.media.m).replace("_m.","_s."))
.attr("alt", item.title)
.appendTo("ul#flickr")
.wrap("<li><a href=\"" + item.link + "\"></a></li>");
if (i == 9) return false;
});
},
error: function(XHR, textStatus, errorThrown){
alert("ERREUR: " + textStatus);
alert("ERREUR: " + errorThrown);
}
});
});
Une solution si vous êtes bloqué avec jQuery 1.4:
var timeout = 10000;
var id = setTimeout( errorCallback, timeout );
$.ajax({
dataType: 'jsonp',
success: function() {
clearTimeout(id);
...
}
});
Cela peut être une limitation "connue" de jQuery; cependant, il ne semble pas bien documenté. J'ai passé environ 4 heures aujourd'hui à essayer de comprendre pourquoi mon délai d'attente ne fonctionnait pas.
Je suis passé à jquery.jsonp et cela a fonctionné comme un charme. Merci.
Semble être résolu à partir de jQuery 1.5. J'ai essayé le code ci-dessus et je reçois le rappel.
Je dis "semble être" parce que la documentation du rappel d'erreur pour jQuery.ajax () a toujours la note suivante:
Remarque: Ce gestionnaire n'est pas appelé pour les requêtes inter-domaines de script et JSONP.
Le plugin jquery-jsonp jQuery mentionné dans Jose Basilio'sanswer peut maintenant être trouvé sur GitHub .
Malheureusement, la documentation est quelque peu spartiate, j'ai donc fourni un exemple 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"
}
});
Important Inclut le callbackParameter dans l'appel $ .jsonp () sinon j'ai trouvé que la fonction de rappel n'est jamais injectée dans la chaîne de requête de l'appel de service (à jour à partir de la version 2.4.0 de jquery-jsonp).
Je sais que cette question est ancienne, mais le problème de la gestion des erreurs à l'aide de JSONP n'est toujours pas "résolu". J'espère que cette mise à jour aidera les autres, car cette question est la mieux classée au sein de Google pour "la gestion des erreurs jquery jsonp".
Qu'en est-il de l'écoute de l'événement onerror du script? J'ai eu ce problème et je l'ai résolu en corrigeant la méthode de jquery où la balise de script a été créée. Voici le morceau de code intéressant:
// 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;
}
Que pensez-vous de cette solution? Est-il susceptible de provoquer des problèmes de compatibilité?