33 Stimmen

jQuery AJAX feuert Fehler-Callback auf Fenster unload - wie kann ich herausfiltern unload und nur echte Fehler zu fangen?

Wenn ich weg von einer Seite in der Mitte eines $.ajax() Anfrage navigieren es den Fehler-Callback auslöst. Ich habe in Safari und FF sowohl mit GET- als auch mit POST-Anfragen getestet.

Eine mögliche Lösung wäre, alle AJAX-Anfragen beim Entladen der Seite abzubrechen, aber der Error-Handler wird vor dem Entladen aufgerufen, so dass dies nicht möglich scheint.

Ich möchte in der Lage sein, REAL Fehler wie 500s anmutig auf der Client-Seite mit einer höflichen Warnung oder einem modalen Dialog zu behandeln, aber ich möchte nicht, dass diese Behandlung aufgerufen werden, wenn ein Benutzer weg von der Seite navigiert.

Wie kann ich das tun?

--

(Auch seltsam: Wenn man von einer Seite weg navigiert, sagt der Error-Handler, dass der textStatus-Parameter "error" ist, derselbe, den er auswirft, wenn er eine 500/schlechte Anfrage erhält).

2 Stimmen

Höflichkeitsalarm - Gibt es so etwas?

0 Stimmen

Jetzt stehe ich vor der gleichen Situation wie Sie, Graham. Danke für den Beitrag!

0 Stimmen

24voto

Christian C. Salvadó Punkte 763569

Im Fehler-Callback oder $.ajax haben Sie drei Eingabeargumente:

function (XMLHttpRequest, textStatus, errorThrown) {
   this; // options for this ajax request
}

Sie können direkt die xhr.status um z.B. den HTTP-Antwortcode zu erhalten:

$.ajax({
  url: "test.html",
  cache: false,
  success: function(html){
    $("#results").append(html);
  },
  error: function (xhr, textStatus) {
    if (xhr.status == 500) {
      alert('Server error: '+ textStatus);
    }
  }
});

Editar: Zur Unterscheidung zwischen einer vom Browser unterbrochenen Verbindung und dem Fall, dass der Server ausgefallen ist (Kommentar von jasonmerino):

Beim Entladen sollte der xhr.readyState 0 sein, während bei einem nicht reagierenden Server der xhr.readyState 4 sein sollte.

3 Stimmen

Status = 0 auch wenn der Server nicht antwortet (ausgefallen ist).

2 Stimmen

Da es den gleichen Statuswert hat, wie kann man zwischen Entladen und nicht reagieren unterscheiden?

5 Stimmen

Beim Entladen wird die xhr.readyState sollte 0 sein, wobei bei einem nicht ansprechbaren Server der xhr.readyState sollte 4 sein.

13voto

Leopd Punkte 39216

Es ist schwierig, dies in allen Situationen richtig zu handhaben. Leider wird in vielen gängigen Browsern die xhr.status dasselbe ist ( 0 ), wenn der AJAX-Aufruf durch die Navigation oder durch einen ausgefallenen/unempfänglichen Server abgebrochen wird. Diese Technik funktioniert also selten.

Hier ist eine Reihe von sehr "praktischen" Hacks, die ich angesammelt habe, die in den meisten Fällen recht gut funktionieren, aber immer noch nicht absolut sicher sind. Die Idee ist, zu versuchen, die Navigationsereignisse abzufangen und ein Flag zu setzen, das im AJAX-Fehlerhandler überprüft wird. Etwa so:

var global_is_navigating = false;

$(window).on('beforeunload',function() {
    // Note: this event doesn't fire in mobile safari
    global_is_navigating = true;
});

$("a").on('click',function() {
    // Giant hack that can be helpful with mobile safari
    if( $(this).attr('href') ) {
        global_is_navigating = true;
    }
});

$(document).ajaxError(function(evt, xhr, settings) {
    // default AJAX error handler for page
    if( global_is_navigating ) {
        // AJAX call cancelled by navigation. Not a real error
        return;
    }
    // process actual AJAX error here.
});

1 Stimmen

Danke für die Lösung, mir ist nur ein Tippfehler im Code aufgefallen. Am Ende des Codes fehlt eine Klammer und ein Doppelpunkt. Also die letzte Methode wird wie folgt aussehen. $(document).ajaxError(function(evt, xhr, settings) { // default AJAX error handler for page if( global_is_navigating ) { // AJAX call cancelled by navigation. Not a real error return; } });

0 Stimmen

Zu Ihrer Information: Der Workaround für die mobile Version von Safari ist auch für iOS 10 erforderlich.

0 Stimmen

Wichtig - missgebildete Ankerlinks lösen manchmal falsche Entladeereignisse aus. Um sich dagegen zu schützen, füge ich setTimeout(function(){global_is_navigating = false;}, 1000) in den Handler ein - wenn eine Sekunde vergangen ist und wir noch am Leben sind und den Timer ausführen konnten, dann war es eine falsche Entladung und die nächsten Fehler sollten nicht ignoriert werden. Problem - natürlich kann während dieser 1 Sekunde ein aktueller AJAX-Fehler auftreten und wir könnten diesen übersehen...

4voto

RedYeti Punkte 961

(Ich würde dies als Kommentar zur Hauptantwort hinzufügen, aber ich habe noch nicht genug Punkte gesammelt, um dies zu tun!)

Ich sehe das auch in FF4 und Chrome (9.0.597.107). Wahrscheinlich anderswo, aber das ist schlimm genug für mich, um es zu beheben wollen!

Eines der Dinge, die über diese Situation seltsam ist, dass zurückgegeben XMLHttpRequest.status === 0

Das scheint ein zuverlässiger Weg zu sein, um diese Situation zu erkennen und, in meinem speziellen Fall, die benutzerdefinierte Fehlerbehandlung, die dem Benutzer angezeigt wird, abzubrechen:

error: function (XMLHttpRequest, textStatus, errorThrown) {
    if (XMLHttpRequest.status === 0) return;
    // error handling here
}

Auch erwähnenswert, dass auf der Annahme, wenn kann ein Problem in der JSON-Parse von was auch immer der Browser gibt zurück zu den $.ajax() aufrufen, habe ich auch versucht, tauschen Sie die native JSON.stringify für die Douglas Crockford Version ( https://github.com/douglascrockford/JSON-js ), aber das machte keinen Unterschied.

4 Stimmen

Status = 0 auch wenn der Server nicht antwortet (ausgefallen ist).

0 Stimmen

Ich habe gerade experimentiert und ja - die 0 wird zurückgegeben, wenn der HTTP-Server (Apache in meinem Fall) entweder bereits unten ist, wenn die Anforderung gemacht wird, oder beendet wird, während die Anforderung mit dem app-Server (JBoss in meinem Fall) ist.

0 Stimmen

Was auch immer es wert ist: Das Beenden des App-Servers mitten in der Anfrage (ich hielt es an einem Haltepunkt) gab mir einen 502-Status zurück, während ich eine 503 erhielt, wenn der App-Server nicht lief, als ich die Anfrage stellte (der HTTP-Server lief natürlich beide Male).

0voto

great_llama Punkte 11167

Der Fehler-Callback sollte einen Verweis auf das XHR-Objekt erhalten, überprüfen Sie den Statuscode, um zu sehen, ob es ein Serverfehler ist oder nicht?

0voto

Alvaro Punkte 39181

Wenn Sie jQuery-Funktionen verwenden, wie z. B. $.get , $.post , $.ajax ... dann können Sie den Parameter text_status um zu prüfen, um welche Art von Fail es sich handelt:

request = $.get('test.html', function(data){
    //whatever
}).fail(function(xhr, text_status, error_thrown) {

    if(text_status!== 'abort'){
        console.warn("Error!!");
    }
});

Desde el jQuery-Dokumente :

jqXHR.fail(function( jqXHR, textStatus, errorThrown ) {}); Ein alternatives Konstrukt zur Fehlerrückrufoption, die Methode .fail() ersetzt die veraltete .error()-Methode. Siehe deferred.fail() für Implementierungsdetails.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X