JQuery Ajax: cómo detectar un error de conexión de red al realizar una llamada Ajax

91

Tengo un código de Javascript JQuery que hace una llamada Ajax al servidor cada 5 minutos, es para mantener viva la sesión del servidor y mantener al usuario conectado. Estoy usando el $.ajax()método en JQuery. Esta función parece tener una propiedad de 'error' que estoy tratando de usar en caso de que la conexión a Internet del usuario se interrumpa para que la secuencia de comandos KeepAlive continúe ejecutándose. Estoy usando el siguiente 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);
        }
    });
}

Cuando lo ejecuto, aparece la ventana emergente 'Éxito' en la pantalla en un cuadro de alerta cada 10 segundos, lo cual está bien. Sin embargo, tan pronto como desconecto el cable de red, no obtengo nada, esperaba que se llamara a la función de error y vea un cuadro de alerta de 'Fallo', pero no sucede nada.

¿Estoy en lo cierto al suponer que la función 'error' es solo para códigos de estado que no son '200' devueltos por el servidor? ¿Existe alguna forma de detectar problemas de conexión de red al realizar una llamada Ajax?

Domingo Ironfoot
fuente
¿Desenchufó el cable de red del cliente o el cable de red del servidor?
Jeff Sternal
¿Continúas recibiendo la alerta de 'éxito' después de desconectar tu conexión?
Wilkins
3
@Jeff: es la pérdida de conexión a Internet en el extremo del cliente lo que está causando el problema. Increíblemente, esto está sucediendo ya que algunos clientes usan la aplicación con una conexión inalámbrica poco fiable que sigue cayendo. Hay un dicho "Nunca subestimes la capacidad de los usuarios finales para encontrar formas de romper tu aplicación", definitivamente suena cierto aquí :-)
Sunday Ironfoot
@qwertypants - No, no pasa nada una vez que se pierde la conexión a Internet (por ejemplo, desconectando el cable). Aunque se hizo el intento de $ .ajax, puedo verlo en Firebug.
Domingo Ironfoot
¿Hay alguna forma de establecer el tiempo de espera para el intento de conexión?
axk

Respuestas:

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
fuente
4
Esta debería ser la respuesta aceptada. En la función de error que proporciona a $ .ajax, el primer parámetro proporciona todo tipo de información de estado. Lo hace incluso si no establece un tiempo de espera.
Mike Spear
Y hacer lo mismo con una forma ajax: <form ... data-ajax-failure="YourMethod" ...></form>y en su métodofunction YourMethod(XMLHttpRequest) { ..same code... }
Matthieu Charbonnier
1
Para obtener más información, XMLHttpRequest.readyStateconsulte ajax_xmlhttprequest_response.asp
stomy
13

Solo debes agregar: en timeout: <number of miliseconds>,algún lugar dentro $.ajax({}). Además, cache: false,podría ayudar en algunos escenarios.

$ .ajax está bien documentado , debe verificar las opciones allí, podría encontrar algo útil.

¡Buena suerte!

Krule
fuente
1
hay muchas cosas que no están documentadas en absoluto en Ajax y de alguna manera están ocultas :(
Espanta
9

Como no puedo duplicar el problema, solo puedo sugerir que lo intente con un tiempo de espera en la llamada ajax. En jQuery, puede configurarlo con $ .ajaxSetup (y será global para todas sus llamadas $ .ajax) o puede configurarlo específicamente para su llamada de esta manera:

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

JQuery registrará un tiempo de espera de 15 segundos en su llamada; después de eso, sin un código de respuesta http del servidor, jQuery ejecutará la devolución de llamada de error con el valor textStatus establecido en "timeout". Con esto, al menos puede detener la llamada ajax, pero no podrá diferenciar los problemas reales de la red de la pérdida de conexiones.

Marco Z
fuente
3

Lo que veo en este caso es que si tiro del cable de red de la máquina cliente y hago la llamada, se llama al manejador de éxito ajax (por qué, no lo sé) y el parámetro de datos es una cadena vacía. Entonces, si descarta el manejo real de errores, puede hacer algo como esto:

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

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

Si está realizando un dominio cruzado, llame a Use Jsonp. de lo contrario, el error no se devuelve.

Swapnil Rebello
fuente
0

UTILIZAR

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

};

(más código a continuación - EJEMPLO DE CARGA DE IMAGEN)

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

esto es lo que hice para alertar al usuario en caso de que su red se cayera o cuando fallara la actualización de la página:

  1. Tengo una etiqueta div en la página donde pongo la hora actual y actualizo esta etiqueta cada 10 segundos. Se parece a esto:<div id="reloadthis">22:09:10</div>

  2. Al final de la función javascript que actualiza la hora en la etiqueta div, pongo esto (después de que la hora se actualice con AJAX):

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

¡Eso es! Puede reemplazar la parte de alerta con cualquier cosa que desee, por supuesto. Espero que esto ayude.

kummik
fuente
-6

¿Has probado esto?

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

Eso debería manejar todos los AjaxErrors. Lo encontré aquí . Allí también encontrará la posibilidad de escribir estos errores en su consola Firebug.

MaikL80
fuente