2009-06-16 12 views
89

Um eine grundlegende Fehlerbehandlung hinzuzufügen, wollte ich ein Stück Code umschreiben, das jQuerys $ .getJSON verwendet, um einige Fotos von Flickr einzufügen. Der Grund dafür ist, dass $ .getJSON keine Fehlerbehandlung bietet oder mit Timeouts arbeitet.jQuery ajax (jsonp) ignoriert ein Zeitlimit und löst kein Fehlerereignis aus

Da $ .getJSON nur ein Wrapper um $ .ajax ist, habe ich beschlossen, das Ding neu zu schreiben und überraschen, es funktioniert einwandfrei.

Jetzt beginnt der Spaß aber. Wenn ich absichtlich einen 404 verursache (indem ich die URL ändere) oder das Netzwerk zu einem Timeout veranlassen (indem ich nicht an die Interwebs angeschlossen werde), wird das Fehlerereignis überhaupt nicht ausgelöst. Ich weiß nicht, was ich falsch mache. Hilfe wird sehr geschätzt.

Hier ist der 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); 
     } 
    }); 

}); 

ich hinzufügen möchten, dass diese Frage gestellt wurde, als jQuery auf Version 1.4.2

Antwort

85

jQuery 1.5 und höher haben bessere Unterstützung für die Fehlerbehandlung mit JSONP-Anfragen. Sie müssen jedoch die $.ajax-Methode anstelle von $.getJSON verwenden. Für mich ist dies funktioniert:

var req = $.ajax({ 
    url : url, 
    dataType : "jsonp", 
    timeout : 10000 
}); 

req.success(function() { 
    console.log('Yes! Success!'); 
}); 

req.error(function() { 
    console.log('Oh noes!'); 
}); 

Der Timeout scheint den Trick und rufen Sie die Fehlerbehandlung zu tun, wenn es keine erfolgreiche Anforderung nach 10 Sekunden.

Ich habe ein wenig blogpost zu diesem Thema auch.

+23

Ich bin jetzt darüber hinaus genervt, dass ich seit 2 Tagen mit Kopf gegen dieses Problem geschlagen habe und es braucht eine obskure Suche in StackOverflow, um herauszufinden, dass ich eine domainübergreifende Anforderung hinzufügen muss, um den Fehler auszulösen.Wie kann dies in der jQuery-Dokumentation nicht erwähnt werden? Sind domänenübergreifende JSON-Anfragen wirklich ungewöhnlich? ? In jedem Fall, danke, danke, danke. +1 – chrixian

+0

Mit dieser Lösung kann ich nicht den Statuscode bekommen, ich bekomme stattdessen "timeout". Also kann ich nicht wissen, was ist der eigentliche Fehler, und kann damit nicht umgehen Eigenschaft – Tarlog

+10

@Tarlog: Das ist logisch. JSONP-Anfragen sind keine nativen Ajax-Anfragen, sondern nur Javascript '

67

war Dies ist eine bekannte Einschränkung mit der nativen JSONP Implementierung in jQuery . Der folgende Text ist von IBM DeveloperWorks

JSONP ist eine sehr leistungsfähige Technik für Gebäude Mashups, aber leider es ist kein Allheilmittel für alle Ihre domänenübergreifende Kommunikation. Es hat einige Nachteile, die in ernsthafte Rücksicht genommen werden müssen, bevor Entwicklung Ressourcen verpflichtet. In erster Linie gibt es keinen Fehler Behandlung für JSONP-Aufrufe. Wenn die dynamische Skripteinfügung funktioniert, werden Sie aufgerufen; wenn nicht, passiert nichts. Es schlägt einfach still. Zum Beispiel Sie sind nicht in der Lage, einen 404-Fehler vom Server abzufangen. Sie können die Anfrage auch nicht abbrechen oder neustarten. Sie können jedoch Timeout nach dem Warten auf eine angemessene Menge an Zeit. (Zukunft jQuery Versionen kann eine Abbruch Funktion haben für JSONP Anfragen.)

Allerdings gibt es ein JSONP Plug-in auf GoogleCode, die Unterstützung für die Fehlerbehandlung zur Verfügung stellt. Um zu beginnen, nehmen Sie einfach die folgenden Änderungen an Ihrem Code vor.

Sie können entweder herunterladen, oder fügen Sie einfach eine Skriptverweis auf das Plug-in.

<script type="text/javascript" 
    src="http://jquery-jsonp.googlecode.com/files/jquery.jsonp-1.0.4.min.js"> 
</script> 

dann Ihren Ajax-Aufruf ändern, wie unten dargestellt:

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

Danke für deine Antwort José! Die begrenzte Implementierung von nativem jsonp in jQuery war der Grund, warum ich stattdessen $ .ajax verwendet habe. Es scheint jedoch, dass das Problem nicht darin besteht, dass $ .getJSON ein Wrapper um $ .ajax ist, sondern der dataType: jsonp. Ist das korrekt? – Matijs

+0

Das ist genau richtig. –

+0

Habe bis heute keine Zeit gehabt. Es funktioniert aber nicht. Ich erhalte einen Fehler, aber das ist alles. Ich weiß nicht, welcher Fehler als errorThrown nicht definiert ist. Für jetzt bleibe ich bei $ .ajax und das Fehlen von Fehlermeldungen. Javascript ist eine zusätzliche Ebene oben auf der Webseite für mich. Wenn Flickr unten ist oder Fehlermeldungen ausgibt, müssen wir nur damit leben :) Danke für deinen Vorschlag. – Matijs

8

Dies kann eine "bekannte" Einschränkung von jQuery sein; es scheint jedoch nicht gut dokumentiert zu sein. Ich habe heute ungefähr 4 Stunden damit verbracht, zu verstehen, warum meine Zeitüberschreitung nicht funktioniert hat.

Ich wechselte zu jquery.jsonp und es funktionierte wie ein Charme. Vielen Dank.

2

Scheint wie von jQuery 1.5 gelöst werden. Ich habe den obigen Code ausprobiert und erhalte den Rückruf.

ich sage „scheint zu sein,“ für jQuery.ajax() noch die folgende Notiz hat, weil die Dokumentation des Fehlers Rückruf:

Hinweis: Dieser Handler nicht für Cross-Domain-Skript und JSONP Anfragen aufgerufen wird.

12

Eine Lösung, wenn Sie mit jQuery stecken 1.4:

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

Danke! Funktioniert für mich – Marek

+2

nur eine Bemerkung, es ist eine gültige Lösung für Leute, die mit 1.4 festhalten, aber setzen Sie Ihre Timeout-Variable hoch genug, damit Sie keine Probleme mit langsamen Webservices haben :). Wenn Sie es zum Beispiel auf eine Sekunde setzen, können Sie sehen, was ich meine, der Fehler Callback wird ausgelöst, während nach dieser 1 Sekunde Ihr Aufruf noch abgerufen wird und die Erfolgsfunktion aufruft. Denken Sie also daran, es ausreichend hoch zu setzen – Sander

+0

@Sander die Erfolgsfunktion könnte sogar aufgerufen werden, wenn Sie eine Antwort nach 10 Sekunden mit einem Timeout von 5 Sekunden erhalten haben. Das Aufrufen von '.abort()' auf einem ausstehenden jqXHR nach einer Zeitüberschreitung könnte ein besserer Weg sein. – Matijs

1

Die jQuery-JSONP jQuery-Plugin in Jose Basilio'sanswer erwähnt kann nun auf GitHub finden.

$.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" 
     } 
    }); 

Wichtige die callbackParameter im Aufruf $ .jsonp() sonst habe ich, dass der Rückruf gefunden umfassen:

Leider ist die Dokumentation etwas spartanisch, ein einfaches Beispiel so habe ich zur Verfügung gestellt Die Funktion wird niemals in die Abfragezeichenfolge des Serviceaufrufs eingefügt (aktuell ab Version 2.4.0 von jquery-jsonp).

Ich weiß, diese Frage ist alt, aber das Problem der Fehlerbehandlung mit JSONP ist immer noch nicht "gelöst". Hoffentlich wird dieses Update anderen helfen, da diese Frage in Google bei "jquery jsonp error handling" ganz oben steht.

+0

nice find, und erstaunlich, dieser Thread lebt noch nach drei Jahren ... – Matijs

1

Wie wäre es mit dem Onerror-Ereignis des Skripts? Ich hatte dieses Problem und löste es, indem ich die Methode von jquery patchen, in der das Skript-Tag erstellt wurde. Hier ist das interessante Bit des Codes:

// 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; 
} 

Was halten Sie von dieser Lösung? Kann es Kompatibilitätsprobleme verursachen?