jQuery ajax (jsonp) ignoriert eine Zeitüberschreitung und löst das Fehlerereignis nicht aus

89

Um einige grundlegende Fehlerbehandlungen hinzuzufügen, wollte ich einen Code neu schreiben, der jQuerys $ .getJSON verwendete, um einige Fotos von Flickr abzurufen. Der Grund dafür ist, dass $ .getJSON keine Fehlerbehandlung bietet oder nicht mit Zeitüberschreitungen arbeitet.

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

Jetzt fängt der Spaß aber an. Wenn ich absichtlich einen 404 verursache (indem ich die URL ändere) oder das Netzwerk eine Zeitüberschreitung verursacht (indem ich nicht mit den Interwebs verbunden bin), 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 möchte hinzufügen, dass diese Frage gestellt wurde, als jQuery auf Version 1.4.2 war

Matijs
quelle

Antworten:

86

jQuery 1.5 und höher unterstützen die Fehlerbehandlung bei JSONP-Anforderungen besser. Sie müssen jedoch die $.ajaxMethode anstelle von verwenden $.getJSON. Für mich funktioniert das:

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

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

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

Das Timeout scheint den Trick zu tun und den Fehlerbehandler aufzurufen, wenn nach 10 Sekunden keine erfolgreiche Anforderung vorliegt.

Ich habe auch einen kleinen Blogpost zu diesem Thema gemacht.

Heiser
quelle
23
Ich bin im Moment überaus verärgert, dass ich 2 Tage lang gegen dieses Problem gekämpft habe und es eine obskure Suche in StackOverflow erfordert, um herauszufinden, dass ich einer domänenübergreifenden Anfrage eine Zeitüberschreitung hinzufügen muss, damit der Fehler ausgelöst wird. Wie kann dies nicht in der jQuery-Dokumentation erwähnt werden? Sind domänenübergreifende Jsonp-Anfragen wirklich so ungewöhnlich? Auf jeden Fall danke, danke, danke. +1
chrixian
Mit dieser Lösung kann ich den Statuscode nicht erhalten, sondern erhalte stattdessen eine "Zeitüberschreitung". Ich kann also nicht wissen, was der eigentliche Fehler ist, und kann die Eigenschaft nicht behandeln.
Tarlog
10
@Tarlog: das ist logisch. JSONP-Anforderungen sind keine nativen Ajax-Anforderungen, sondern lediglich Javascript- <script>Tags, die dynamisch eingefügt werden. Das einzige, was Sie daher wissen können, ist, dass eine Anforderung fehlgeschlagen ist und nicht der Statuscode. Wenn Sie Statuscodes erhalten möchten, müssen Sie herkömmliche Ajax-Anforderungen oder andere domänenübergreifende Techniken verwenden.
Husky
1
Wie @Husky sagte, können Sie mit JSONP keine Statuscodes haben, und ich glaube, deshalb sollten Sie versuchen, dies zu vermeiden. Die einzige Möglichkeit, einen Fehler zu erhalten, besteht darin, eine Zeitüberschreitung zu verursachen. Dies sollte in der jQuery-Dokumentation besser erklärt werden (wie viele andere Dinge auch).
Alejandro García Iglesias
67

Dies ist eine bekannte Einschränkung bei der nativen jsonp-Implementierung in jQuery. Der folgende Text stammt von IBM DeveloperWorks

JSONP ist eine sehr leistungsfähige Technik zum Erstellen von Mashups, aber leider nicht das Allheilmittel für alle Ihre domänenübergreifenden Kommunikationsanforderungen. Es hat einige Nachteile, die ernsthaft berücksichtigt werden müssen, bevor Entwicklungsressourcen bereitgestellt werden. In erster Linie gibt es keine Fehlerbehandlung für JSONP-Aufrufe. Wenn das dynamische Einfügen von Skripten funktioniert, werden Sie aufgerufen. wenn nicht, passiert nichts. Es scheitert einfach lautlos. Beispielsweise können Sie keinen 404-Fehler vom Server abfangen. Sie können die Anforderung auch nicht abbrechen oder neu starten. Sie können jedoch eine Zeitüberschreitung feststellen, nachdem Sie eine angemessene Zeit gewartet haben. (Zukünftige jQuery-Versionen verfügen möglicherweise über eine Abbruchfunktion für JSONP-Anforderungen.)

Allerdings gibt es eine JSONP Plug-in auf Googlecode, die Unterstützung für die Fehlerbehandlung zur Verfügung stellt. Nehmen Sie zunächst die folgenden Änderungen an Ihrem Code vor.

Sie können es entweder herunterladen oder einfach eine Skriptreferenz zum Plug-In hinzufügen.

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

Ändern Sie dann Ihren Ajax-Aufruf wie folgt:

$(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);
        }
    });
});
Jose Basilio
quelle
Danke, dass du José antwortest! Die eingeschränkte Implementierung von nativem jsonp in jQuery war der Grund, warum ich mich stattdessen für $ .ajax entschieden habe. Dann scheint das Problem jedoch nicht zu sein, dass $ .getJSON ein Wrapper um $ .ajax ist, sondern der Datentyp: jsonp. Ist das korrekt?
Matijs
Ich hatte bis heute keine Zeit. Es funktioniert jedoch nicht. Ich erhalte eine Fehlermeldung, aber das war es auch schon. Ich weiß nicht, welcher Fehler als errorThrown undefiniert ist. Im Moment bleibe ich bei $ .ajax und dem Fehlen von Fehlermeldungen. Javascript ist für mich eine zusätzliche Ebene über der Webseite. Wenn Flickr nicht funktioniert oder Fehlermeldungen ausgibt, müssen wir erst einmal damit leben :) Vielen Dank für Ihren Vorschlag.
Matijs
Grundsätzlich sollte Josés Vorschlag, das jsonp-Plugin zu verwenden, funktionieren, wenn es richtig gemacht wird. Im Moment bleibe ich jedoch beim grundlegenden json-Wrapper für jQuery.
Matijs
Dies funktionierte hervorragend für mich, als ich mit den eingebauten Einschränkungen der Fehlerbehandlung von jsonp an die Wand gestoßen war
Jeremy Frey
7
Ein anderer Entwickler hat diesen Tipp gespeichert. Vielen Dank!
Chesterbr
12

Eine Lösung, wenn Sie mit jQuery 1.4 nicht weiterkommen:

var timeout = 10000;
var id = setTimeout( errorCallback, timeout );
$.ajax({
    dataType: 'jsonp',
    success: function() {
        clearTimeout(id);
        ...
    }
});
Rob De Almeida
quelle
2
Nur eine Bemerkung, es ist eine gültige Lösung für Leute, die mit 1.4 stecken, aber setzen Sie Ihre Timeout-Variable hoch genug, damit Sie keine Probleme mit langsamen Webservices haben :). Wenn Sie es zum Beispiel auf eine Sekunde einstellen, können Sie sehen, was ich meine, der Fehlerrückruf wird ausgelöst, während nach dieser 1 Sekunde Ihr Anruf immer noch abgerufen wird und die Erfolgsfunktion aufruft. Denken Sie also daran, es einigermaßen hoch genug einzustellen
Sander
@Sander Die Erfolgsfunktion könnte sogar aufgerufen werden, wenn Sie nach 10 Sekunden eine Antwort mit einer Zeitüberschreitung von 5 Sekunden erhalten. Das Aufrufen .abort()eines ausstehenden jqXHR nach einer Zeitüberschreitung ist möglicherweise besser.
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 Auszeit nicht funktioniert hat.

Ich wechselte zu jquery.jsonp und es funktionierte wie ein Zauber. Danke dir.

Marc
quelle
2

Scheint ab jQuery 1.5 gelöst zu sein. Ich habe den obigen Code ausprobiert und erhalte den Rückruf.

Ich sage "scheint zu sein", weil die Dokumentation des Fehlerrückrufs für jQuery.ajax () immer noch den folgenden Hinweis enthält:

Hinweis: Dieser Handler wird nicht für domänenübergreifende Skript- und JSONP-Anforderungen aufgerufen.

Peter Tate
quelle
1

Das in Jose Basilios Antwort erwähnte jQuery-Plugin jquery-jsonp ist jetzt auf GitHub zu finden .

Leider ist die Dokumentation etwas spartanisch, daher habe ich ein einfaches Beispiel gegeben:

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

Wichtig Fügen Sie den callbackParameter in den Aufruf $ .jsonp () ein. Andernfalls wurde festgestellt, dass die Rückruffunktion niemals in die Abfragezeichenfolge des Serviceaufrufs eingefügt wird (aktuell ab Version 2.4.0 von jquery-jsonp).

Ich weiß, dass diese Frage alt ist, aber das Problem der Fehlerbehandlung mit JSONP ist immer noch nicht gelöst. Hoffentlich hilft dieses Update anderen, da diese Frage bei Google für "jquery jsonp error handle" an erster Stelle steht.

OiDatsMyLeg
quelle
schöner Fund und erstaunlich, dass dieser Thread nach drei Jahren noch am Leben ist…
Matijs
1

Was ist mit dem Abhören des Fehlerereignisses des Skripts? Ich hatte dieses Problem und löste es durch Patchen der Methode von jquery, in der das Skript-Tag erstellt wurde. Hier ist der interessante Code:

// 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? Ist es wahrscheinlich, dass es Kompatibilitätsprobleme verursacht?

Hadrien Milano
quelle