JQuery Ajax - Como detectar erro de conexão de rede ao fazer uma chamada Ajax

91

Eu tenho algum código Javascript JQuery que faz uma chamada Ajax para o servidor a cada 5 minutos, é para manter a sessão do servidor ativa e manter o usuário conectado. Estou usando o $.ajax()método em JQuery. Esta função parece ter uma propriedade 'error' que estou tentando usar no caso de a conexão do usuário com a Internet cair para que o script KeepAlive continue a ser executado. Estou usando o seguinte código:

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

Quando eu executá-lo, obtenho o pop-up 'Sucesso' na tela em uma caixa de alerta a cada 10 segundos, o que é bom. No entanto, assim que desconecto o cabo de rede, não recebo nada, esperava que a função de erro fosse chamada e veria uma caixa de alerta de 'Falha', mas nada acontece.

Estou correto ao presumir que a função 'erro' é apenas para códigos de status não '200' retornados do servidor? Existe uma maneira de detectar problemas de conexão de rede ao fazer uma chamada Ajax?

Sunday Ironfoot
fonte
Você desconectou o cabo de rede do cliente ou o cabo de rede do servidor?
Jeff Sternal
Você continua recebendo o alerta de 'sucesso' após desconectar sua conexão?
Wilkins
3
@Jeff - É a perda de conexão com a Internet no lado do cliente que está causando o problema. Inacreditavelmente, isso está realmente acontecendo, pois alguns clientes usam o aplicativo com uma conexão sem fio duvidosa que sempre falha. Há um ditado "Nunca subestime a capacidade dos usuários finais de encontrar maneiras de quebrar seu aplicativo", definitivamente soa verdadeiro aqui :-)
Domingo Ironfoot
@qwertypants - Não, nada acontece depois que a conexão com a Internet é perdida (por exemplo, desconectando o cabo). Embora a tentativa de $ .ajax seja feita, posso vê-la no Firebug.
Domingo Ironfoot
Existe uma maneira de definir o tempo limite para a tentativa de conexão?
axk

Respostas:

98
// 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
fonte
4
Esta deve ser a resposta aceita. Na função de erro que você fornece para $ .ajax, o primeiro parâmetro fornece todos os tipos de informações de status. Ele faz isso mesmo se você não definir um tempo limite.
Mike Spear de
E para fazer o mesmo com um formulário ajax: <form ... data-ajax-failure="YourMethod" ...></form>e no seu métodofunction YourMethod(XMLHttpRequest) { ..same code... }
Matthieu Charbonnier
1
Para obter mais informações, XMLHttpRequest.readyStateconsulte ajax_xmlhttprequest_response.asp
stomy
13

Você deve apenas adicionar: em timeout: <number of miliseconds>,algum lugar dentro $.ajax({}). Além disso, cache: false,pode ajudar em alguns cenários.

$ .ajax está bem documentado , você deve verificar as opções lá, pode encontrar algo útil.

Boa sorte!

Krule
fonte
1
há muitas coisas não documentadas no Ajax e de alguma forma escondidas :(
Espanta
9

Como não posso duplicar o problema, só posso sugerir tentar com um tempo limite na chamada de ajax. No jQuery, você pode configurá-lo com $ .ajaxSetup (e será global para todas as suas chamadas $ .ajax) ou pode configurá-lo especificamente para sua chamada desta forma:

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

JQuery registrará um tempo limite de 15 segundos em sua chamada; depois disso, sem um código de resposta http do servidor, o jQuery executará o retorno de chamada de erro com o valor textStatus definido como "timeout". Com isso, você pode pelo menos interromper a chamada ajax, mas não será capaz de diferenciar os problemas reais de rede da perda de conexões.

Marco Z
fonte
3

O que vejo neste caso é que se eu puxar o cabo de rede da máquina cliente e fizer a chamada, o manipulador de sucesso do ajax é chamado (por que, eu não sei), e o parâmetro de dados é uma string vazia. Portanto, se você fatorar o tratamento de erros reais, pode fazer algo assim:

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

jQuery.ajax({
    ...
    success: function(data, textStatus, jqXHR) {
        if (data == "") handleError(jqXHR, "clientNetworkError", "");
    },
    error: handleError
});
Geoff
fonte
1

Se você estiver fazendo vários domínios, ligue para o Use Jsonp. caso contrário, o erro não é retornado.

Swapnil Rebello
fonte
0

USAR

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

};

(mais código abaixo - CARREGAR EXEMPLO DE IMAGEM)

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
fonte
-1

aqui está o que eu fiz para alertar o usuário no caso de sua rede cair ou ocorrer uma falha na atualização da página:

  1. Eu tenho uma div-tag na página onde coloco a hora atual e atualizo essa tag a cada 10 segundos. É mais ou menos assim:<div id="reloadthis">22:09:10</div>

  2. No final da função javascript que atualiza o tempo na div-tag, coloco o seguinte (depois que o tempo é atualizado com AJAX):

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

É isso aí! Você pode substituir a parte de alerta com o que quiser, é claro. Espero que isto ajude.

kummik
fonte
-6

Você já tentou isso?

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

Isso deve lidar com todos os AjaxErrors. Eu encontrei aqui . Lá você também encontra a possibilidade de gravar esses erros no console do Firebug.

MaikL80
fonte