JQuery Ajax - Jak wykryć błąd połączenia sieciowego podczas wykonywania połączenia Ajax

91

Mam kod JavaScript JQuery, który wykonuje wywołanie Ajax do serwera co 5 minut, ma to na celu utrzymanie sesji serwera i zalogowanie użytkownika. Używam $.ajax()metody w JQuery. Wydaje się, że ta funkcja ma właściwość „błąd”, której próbuję użyć w przypadku awarii połączenia internetowego użytkownika, aby skrypt KeepAlive nadal działał. Używam następującego kodu:

var keepAliveTimeout = 1000 * 10;

function keepSessionAlive()
{
    $.ajax(
    {
        type: 'GET',
        url: 'http://www.mywebapp.com/keepAlive',
        success: function(data)
        {
            alert('Success');

            setTimeout(function()
            {
                keepSessionAlive();
            }, keepAliveTimeout);
        },
        error: function(XMLHttpRequest, textStatus, errorThrown)
        {
            alert('Failure');

            setTimeout(function()
            {
                keepSessionAlive();
            }, keepAliveTimeout);
        }
    });
}

Kiedy go uruchomię, co 10 sekund będzie pojawiać się wyskakujące okienko „Sukces” w oknie z ostrzeżeniem. Jednak jak tylko odłączę kabel sieciowy, nic się nie dzieje, spodziewałem się wywołania funkcji błędu i wyświetlenie komunikatu „Awaria”, ale nic się nie dzieje.

Czy mam rację zakładając, że funkcja „błąd” dotyczy tylko kodów statusu innych niż „200” zwracanych z serwera? Czy istnieje sposób na wykrycie problemów z połączeniem sieciowym podczas wykonywania połączenia Ajax?

Niedziela Ironfoot
źródło
Czy odłączyłeś kabel sieciowy klienta lub kabel sieciowy serwera?
Jeff Sternal
Czy nadal otrzymujesz komunikat „sukces” po odłączeniu połączenia?
Wilkins
3
@Jeff - przyczyną problemu jest utrata połączenia internetowego po stronie klienta. Niewiarygodne, że tak się dzieje, ponieważ niektórzy klienci używają aplikacji z podejrzanym połączeniem bezprzewodowym, które ciągle zanika. Jest takie powiedzenie "Nigdy nie lekceważ możliwości użytkowników końcowych w znalezieniu sposobów na złamanie twojej aplikacji", zdecydowanie brzmi tutaj :-)
Niedziela Ironfoot
@qwertypants - Nie, nic się nie dzieje po utracie połączenia internetowego (np. odłączeniu kabla). Chociaż podjęto próbę $ .ajax, widzę to w Firebug.
Niedziela Ironfoot
Czy istnieje sposób na ustawienie limitu czasu próby połączenia?
axk

Odpowiedzi:

99
// start snippet
error: function(XMLHttpRequest, textStatus, errorThrown) {
        if (XMLHttpRequest.readyState == 4) {
            // HTTP error (can be checked by XMLHttpRequest.status and XMLHttpRequest.statusText)
        }
        else if (XMLHttpRequest.readyState == 0) {
            // Network error (i.e. connection refused, access denied due to CORS, etc.)
        }
        else {
            // something weird is happening
        }
    }
//end snippet
Craneum
źródło
4
To powinna być akceptowana odpowiedź. W funkcji błędu, którą przekazujesz do $ .ajax, pierwszy parametr zawiera różnego rodzaju informacje o statusie. Dzieje się tak, nawet jeśli nie ustawisz limitu czasu.
Mike Spear,
I zrobić to samo z formularzem Ajax: <form ... data-ajax-failure="YourMethod" ...></form>i na swojej metodziefunction YourMethod(XMLHttpRequest) { ..same code... }
Matthieu Charbonnier
1
Więcej informacji na temat XMLHttpRequest.readyStatepatrz ajax_xmlhttprequest_response.asp
Stomy
13

Wystarczy dodać: timeout: <number of miliseconds>,gdzieś w środku $.ajax({}). Ponadto, cache: false,może pomóc w kilku scenariuszy.

$ .ajax jest dobrze udokumentowane , powinieneś sprawdzić tam opcje, może znajdziesz coś przydatnego.

Powodzenia!

Krule
źródło
1
jest wiele rzeczy, które w ogóle nie są udokumentowane w Ajaxie i są w jakiś sposób ukryte :(
Espanta,
9

Ponieważ nie mogę powielić problemu, mogę tylko zasugerować, aby spróbować z przekroczeniem limitu czasu w wywołaniu Ajax. W jQuery możesz ustawić to za pomocą $ .ajaxSetup (i będzie to globalne dla wszystkich twoich wywołań $ .ajax) lub możesz ustawić to specjalnie dla swojego wywołania w następujący sposób:

$.ajax({
    type: 'GET',
    url: 'http://www.mywebapp.com/keepAlive',
    timeout: 15000,
    success: function(data) {},
    error: function(XMLHttpRequest, textStatus, errorThrown) {}
})

JQuery zarejestruje 15-sekundowy limit czasu połączenia; po tym bez kodu odpowiedzi http z serwera jQuery wykona wywołanie zwrotne błędu z wartością textStatus ustawioną na „timeout”. Dzięki temu możesz przynajmniej zatrzymać połączenie Ajax, ale nie będziesz w stanie odróżnić rzeczywistych problemów z siecią od utraty połączeń.

Marco Z
źródło
3

W tym przypadku widzę, że jeśli wyciągnę kabel sieciowy maszyny klienta i wykonam wywołanie, zostanie wywołana procedura obsługi AJAX (dlaczego, nie wiem), a parametr danych jest pustym ciągiem. Więc jeśli weźmiesz pod uwagę rzeczywistą obsługę błędów, możesz zrobić coś takiego:

function handleError(jqXHR, textStatus, errorThrown) {
    ...
}

jQuery.ajax({
    ...
    success: function(data, textStatus, jqXHR) {
        if (data == "") handleError(jqXHR, "clientNetworkError", "");
    },
    error: handleError
});
Geoff
źródło
1

Jeśli wykonujesz międzydomenę, wywołaj metodę Use Jsonp. w przeciwnym razie błąd nie zostanie zwrócony.

Swapnil Rebello
źródło
0

POSŁUGIWAĆ SIĘ

xhr.onerror = function(e){
    if (XMLHttpRequest.readyState == 4) {
        // HTTP error (can be checked by XMLHttpRequest.status and XMLHttpRequest.statusText)
        selFoto.erroUploadFoto('Erro HTTP: '+XMLHttpRequest.statusText);
    }
    else if (XMLHttpRequest.readyState == 0) {
        // Network error (i.e. connection refused, access denied due to CORS, etc.)
        selFoto.erroUploadFoto('Erro de rede:'+XMLHttpRequest.statusText);
    }
    else {
        selFoto.erroUploadFoto('Erro desconhecido.');
    }

};

(więcej kodu poniżej - PRZEŚLIJ PRZYKŁAD OBRAZU)

var selFoto = {
   foto: null,

   upload: function(){
        LoadMod.show();

        var arquivo = document.frmServico.fileupload.files[0];
        var formData = new FormData();

        if (arquivo.type.match('image.*')) {
            formData.append('upload', arquivo, arquivo.name);

            var xhr = new XMLHttpRequest();
            xhr.open('POST', 'FotoViewServlet?acao=uploadFoto', true);
            xhr.responseType = 'blob';

            xhr.onload = function(e){
                if (this.status == 200) {
                    selFoto.foto = this.response;
                    var url = window.URL || window.webkitURL;
                    document.frmServico.fotoid.src = url.createObjectURL(this.response);
                    $('#foto-id').show();
                    $('#div_upload_foto').hide();           
                    $('#div_master_upload_foto').css('background-color','transparent');
                    $('#div_master_upload_foto').css('border','0');

                    Dados.foto = document.frmServico.fotoid;
                    LoadMod.hide();
                }
                else{
                    erroUploadFoto(XMLHttpRequest.statusText);
                }

                if (XMLHttpRequest.readyState == 4) {
                     selFoto.erroUploadFoto('Erro HTTP: '+XMLHttpRequest.statusText);
                }
                else if (XMLHttpRequest.readyState == 0) {
                     selFoto.erroUploadFoto('Erro de rede:'+XMLHttpRequest.statusText);                             
                }

            };

            xhr.onerror = function(e){
            if (XMLHttpRequest.readyState == 4) {
                // HTTP error (can be checked by XMLHttpRequest.status and XMLHttpRequest.statusText)
                selFoto.erroUploadFoto('Erro HTTP: '+XMLHttpRequest.statusText);
            }
            else if (XMLHttpRequest.readyState == 0) {
                 // Network error (i.e. connection refused, access denied due to CORS, etc.)
                 selFoto.erroUploadFoto('Erro de rede:'+XMLHttpRequest.statusText);
            }
            else {
                selFoto.erroUploadFoto('Erro desconhecido.');
            }
        };

        xhr.send(formData);
     }
     else{
        selFoto.erroUploadFoto('');                         
        MyCity.mensagens.push('Selecione uma imagem.');
        MyCity.showMensagensAlerta();
     }
  }, 

  erroUploadFoto : function(mensagem) {
        selFoto.foto = null;
        $('#file-upload').val('');
        LoadMod.hide();
        MyCity.mensagens.push('Erro ao atualizar a foto. '+mensagem);
        MyCity.showMensagensAlerta();
 }
 };
MalucOJonnes
źródło
-1

oto, co zrobiłem, aby ostrzec użytkownika w przypadku awarii sieci lub niepowodzenia aktualizacji strony:

  1. Mam na stronie znacznik DIV, w którym umieszczam aktualny czas i aktualizuję ten tag co 10 sekund. Wygląda mniej więcej tak:<div id="reloadthis">22:09:10</div>

  2. Na końcu funkcji javascript, która aktualizuje czas w znaczniku div, umieściłem to (po aktualizacji czasu za pomocą AJAX):

    var new_value = document.getElementById('reloadthis').innerHTML;
    var new_length = new_value.length;
    if(new_length<1){
        alert("NETWORK ERROR!");
    }
    

Otóż ​​to! Oczywiście możesz zastąpić część ostrzegawczą czymkolwiek zechcesz. Mam nadzieję że to pomoże.

kummik
źródło
-6

Czy próbowałeś tego?

$(document).ajaxError(function(){ alert('error'); }

To powinno obsłużyć wszystkie AjaxErrors. Znalazłem to tutaj . Znajdziesz tam również możliwość zapisania tych błędów na konsoli firebuga.

MaikL80
źródło