Como detectar cross-browser de eventos online / offline?

111

Estou tentando detectar com precisão quando o navegador fica offline, usando os eventos HTML5 online e offline.

Este é o meu código:

<script>
    // FIREFOX
    $(window).bind("online", applicationBackOnline); 
    $(window).bind("offline", applicationOffline);

    //IE
    window.onload = function() {
        document.body.ononline = IeConnectionEvent;
        document.body.onoffline = IeConnectionEvent;
    } 
</script>

Funciona bem quando clico em "Trabalhar offline" no Firefox ou no IE, mas funciona de forma aleatória quando eu realmente desconecto o fio.

Qual é a melhor maneira de detectar essa mudança? Eu gostaria de evitar a repetição de chamadas ajax com tempo limite.

Pierre Duplouy
fonte
2
Eu concordo com a Trefex, mas também gostaria de acrescentar que o suporte à detecção de conexão é de má qualidade, na melhor das hipóteses, para a maioria dos aplicativos: só porque o fio está desconectado não significa que a conexão foi perdida imediatamente. Confiar em um método que não testa fisicamente se a conexão está aberta não pode realmente garantir resultados precisos.
mattbasta
Obrigada pelo Conselho. Então você recomendaria o método Ajax? ie. continuar enviando chamadas XHR com tempo limite?
Pierre Duplouy
A implementação do Firefox (e do IE e do Opera) está errada. Veja meu comentário sobre o
assunto
4
Você pode querer dar uma olhada no Offline.js , uma biblioteca de código aberto construída apenas para este propósito.
Adam

Respostas:

70

Os fornecedores de navegadores não concordam sobre como definir offline. Alguns navegadores têm um recurso Trabalhar Offline, que eles consideram separado da falta de acesso à rede, que novamente é diferente do acesso à Internet. A coisa toda está uma bagunça. Alguns fornecedores de navegadores atualizam o sinalizador navigator.onLine quando o acesso à rede real é perdido, outros não.

Da especificação:

Retorna falso se o agente do usuário estiver definitivamente offline (desconectado da rede). Retorna verdadeiro se o agente do usuário estiver online.

Os eventos online e offline são disparados quando o valor deste atributo muda.

O atributo navigator.onLine deve retornar falso se o agente do usuário não contatar a rede quando o usuário seguir links ou quando um script solicitar uma página remota (ou saber que tal tentativa falhará) e, caso contrário, deve retornar verdadeiro.

Finalmente, as notas de especificações:

Este atributo é inerentemente não confiável. Um computador pode ser conectado a uma rede sem ter acesso à Internet.

Rebecca
fonte
23
Apenas o Chrome define navigator.onLine corretamente quando a conectividade é perdida. Tanto o Safari quanto o Firefox nunca definem o sinalizador como falso se você remover a conexão com a Internet.
chovy,
2
@chovy e que tal agora? Recentemente testei no Firefox / Chrome e obtive os resultados esperados, visto que o sinalizador está sendo definido, quando desligo e ligo a conexão com a internet.
James Cazzetta
12
Hoje, 31/01/2017, abri o OSX Chrome 55.0.2883.95, Safari 10.0.3 e FF 50.1.0. Todo o window.navigator.onLine parece funcionar muito bem quando fiquei na rede, mas removi o cabo do roteador. Todos eles foram detectados offline corretamente.
nycynik
3
navigator.onLine é compatível com todos os principais navegadores (e já há algum tempo): caniuse.com/#feat=online-status
Rafael Lüder
@RafaelLüder Correto a partir de hoje, mas esta resposta foi escrita em janeiro de 2011!
Rebecca
34

Os principais fornecedores de navegadores diferem sobre o que "offline" significa.

O Chrome e o Safari detectarão quando você ficar "offline" automaticamente - o que significa que os eventos e propriedades "online" serão disparados automaticamente quando você desconectar o cabo de rede.

Firefox (Mozilla), Opera e IE adotam uma abordagem diferente e consideram você "online", a menos que você escolha explicitamente "Modo offline" no navegador - mesmo que não tenha uma conexão de rede funcionando.

Existem argumentos válidos para o comportamento do Firefox / Mozilla, que são descritos nos comentários deste relatório de bug:

https://bugzilla.mozilla.org/show_bug.cgi?id=654579

Mas, para responder à pergunta - você não pode confiar nos eventos / propriedades online / offline para detectar se realmente há conectividade de rede.

Em vez disso, você deve usar abordagens alternativas.

A seção "Notas" deste artigo do Mozilla Developer fornece links para dois métodos alternativos:

https://developer.mozilla.org/en/Online_and_offline_events

"Se a API não estiver implementada no navegador, você pode usar outros sinais para detectar se está off-line, incluindo a escuta de eventos de erro AppCache e respostas de XMLHttpRequest"

Este link para um exemplo da abordagem de "escuta de eventos de erro do AppCache":

http://www.html5rocks.com/en/mobile/workingoffthegrid/#toc-appcache

... e um exemplo da abordagem de "escuta de falhas XMLHttpRequest":

http://www.html5rocks.com/en/mobile/workingoffthegrid/#toc-xml-http-request

HTH, - Chad

thewoolleyman
fonte
1
A partir do Firefox 41: updates this property when the OS reports a change in network connectivity on Windows, Linux, and OS X.(de acordo com os documentos que você mencionou). Portanto, não é apenas offline se você estiver navegando com o navegador "Modo offline"
cara
17

Hoje existe uma biblioteca JavaScript de código aberto que faz este trabalho: é chamada Offline.js.

Exibir automaticamente indicação online / offline para seus usuários.

https://github.com/HubSpot/offline

Certifique-se de verificar o README completo . Ele contém eventos aos quais você pode se conectar.

Aqui está uma página de teste . É lindo / tem um bom feedback da IU por falar nisso! :)

Offline.js Simulate UI é um plug-in Offline.js que permite testar como suas páginas respondem a diferentes estados de conectividade sem ter que usar métodos de força bruta para desativar sua conectividade real.

Leniel Maccaferri
fonte
2
A biblioteca, na verdade, funciona buscando favicon local repetidamente sob o capô. Na minha opinião, a biblioteca é muito "grande" e tem muitos recursos; o truque principal é apenas buscar o favicon repetidamente.
Karel Bílek,
1
Não detecta offline quando eu desconecto o cabo de rede
poshest
15

A melhor maneira que funciona agora em todos os navegadores principais é o seguinte script:

(function () {
    var displayOnlineStatus = document.getElementById("online-status"),
        isOnline = function () {
            displayOnlineStatus.innerHTML = "Online";
            displayOnlineStatus.className = "online";
        },
        isOffline = function () {
            displayOnlineStatus.innerHTML = "Offline";
            displayOnlineStatus.className = "offline";
        };

    if (window.addEventListener) {
        /*
            Works well in Firefox and Opera with the 
            Work Offline option in the File menu.
            Pulling the ethernet cable doesn't seem to trigger it.
            Later Google Chrome and Safari seem to trigger it well
        */
        window.addEventListener("online", isOnline, false);
        window.addEventListener("offline", isOffline, false);
    }
    else {
        /*
            Works in IE with the Work Offline option in the 
            File menu and pulling the ethernet cable
        */
        document.body.ononline = isOnline;
        document.body.onoffline = isOffline;
    }
})();

Fonte: http://robertnyman.com/html5/offline/online-offline-events.html

tmaximini
fonte
3
Como os comentários no próprio código afirmam claramente - não funciona no Firefox / Chrome se você desconectar o cabo ethernet ou desligar o wi-fi.
Manish
Tentei visitar o link "Fonte" e desconectei o cabo Ethernet, mas ele mostrou "Você está offline" no IE, mas não no Firefox / Chrome para mim (usando a versão mais recente de todos os navegadores). Posso estar faltando alguma coisa?
Manish
13

Recentemente, navigator.onLinemostra o mesmo em todos os principais navegadores e, portanto, pode ser usado.

if (navigator.onLine) {
  // do things that need connection
} else {
  // do things that don't need connection
}

As versões mais antigas que suportam isso da maneira certa são: Firefox 41 , IE 9, Chrome 14 e Safari 5.

Atualmente, isso representará quase todo o espectro de usuários, mas você deve sempre verificar o que os usuários de sua página têm de recursos.

Anterior ao FF 41, ele só seria mostrado falsese o usuário colocasse o navegador manualmente no modo offline. No IE 8, a propriedade estava no body, em vez de window.

fonte: caniuse

Haroen Viaene
fonte
11

O window.navigator.onLineatributo e seus eventos associados Atualmente não confiável em determinados navegadores da web ( especialmente de desktop Firefox ) como @Junto disse, então eu escrevi um pouco de função (usando jQuery) que verificar periodicamente o estado de conectividade de rede e aumentar a apropriada offlinee onlineevento:

// Global variable somewhere in your app to replicate the 
// window.navigator.onLine variable (it is not modifiable). It prevents
// the offline and online events to be triggered if the network
// connectivity is not changed
var IS_ONLINE = true;

function checkNetwork() {
  $.ajax({
    // Empty file in the root of your public vhost
    url: '/networkcheck.txt',
    // We don't need to fetch the content (I think this can lower
    // the server's resources needed to send the HTTP response a bit)
    type: 'HEAD',
    cache: false, // Needed for HEAD HTTP requests
    timeout: 2000, // 2 seconds
    success: function() {
      if (!IS_ONLINE) { // If we were offline
        IS_ONLINE = true; // We are now online
        $(window).trigger('online'); // Raise the online event
      }
    },
    error: function(jqXHR) {
      if (jqXHR.status == 0 && IS_ONLINE) {
        // We were online and there is no more network connection
        IS_ONLINE = false; // We are now offline
        $(window).trigger('offline'); // Raise the offline event
      } else if (jqXHR.status != 0 && !IS_ONLINE) {
        // All other errors (404, 500, etc) means that the server responded,
        // which means that there are network connectivity
        IS_ONLINE = true; // We are now online
        $(window).trigger('online'); // Raise the online event
      }
    }
  });
}

Você pode usá-lo assim:

// Hack to use the checkNetwork() function only on Firefox 
// (http://stackoverflow.com/questions/5698810/detect-firefox-browser-with-jquery/9238538#9238538)
// (But it may be too restrictive regarding other browser
// who does not properly support online / offline events)
if (!(window.mozInnerScreenX == null)) {
    window.setInterval(checkNetwork, 30000); // Check the network every 30 seconds
}

Para ouvir os eventos offline e online (com a ajuda de jQuery):

$(window).bind('online offline', function(e) {
  if (!IS_ONLINE || !window.navigator.onLine) {
    alert('We have a situation here');
  } else {
    alert('Battlestation connected');
  }
});
Época
fonte
7

navigator.onLine é uma bagunça

Encaro isso ao tentar fazer uma chamada ajax para o servidor.

Existem várias situações possíveis quando o cliente está offline:

  • os tempos limite de chamada ajax e você recebe um erro
  • a chamada ajax retorna sucesso, mas a mensagem é nula
  • a chamada ajax não é executada porque o navegador decide (pode ser quando navigator.onLine se torna falso após um tempo)

A solução que estou usando é controlar o status sozinho com javascript. Defino a condição de chamada bem-sucedida, em qualquer outro caso presumo que o cliente está offline. Algo assim:

var offline;
pendingItems.push(item);//add another item for processing
updatePendingInterval = setInterval("tryUpdatePending()",30000);
tryUpdatePending();

    function tryUpdatePending() {

        offline = setTimeout("$('#offline').show()", 10000);
        $.ajax({ data: JSON.stringify({ items: pendingItems }), url: "WebMethods.aspx/UpdatePendingItems", type: "POST", dataType: "json", contentType: "application/json; charset=utf-8",
          success: function (msg) {
            if ((!msg) || msg.d != "ok")
              return;
            pending = new Array(); //empty the pending array
            $('#offline').hide();
            clearTimeout(offline);
            clearInterval(updatePendingInterval);
          }
        });
      }
Kit de ferramentas
fonte
5

Em HTML5 você pode usar a navigator.onLinepropriedade. Olhe aqui:

http://www.w3.org/TR/offline-webapps/#related

Provavelmente, seu comportamento atual é aleatório, pois o javascript só prepara a variável "navegador" e sabe se você está offline e online, mas não verifica a conexão de rede.

Informe-nos se é isso que você está procurando.

Atenciosamente,

Trefex
fonte
Obrigado pela ajuda Trefex. Mudei meu código, e agora verifico apenas a propriedade navigator.onLine, porém obtenho o mesmo comportamento de antes. Por favor, dê uma olhada no comentário de mattbasta.
Pierre Duplouy
Olá Pedro, concordo com o mattbasta mas espero que funcione para você :) Eu definitivamente usaria o método Ajax para consultar alguma URL que você sabe que está sempre ativa e então você saberia se uma conexão foi perdida ou não. Por outro lado, por que você exige a detecção precisa do status online / offline? Talvez se soubéssemos mais, haveria outra solução para o seu problema. Informe-nos,
Trefex
1
Ok, obrigado :) Achei que seria melhor para o usuário se o aplicativo pudesse detectar automaticamente uma alteração na conectividade (não há necessidade de habilitar manualmente o modo off-line no FF ou IE). Dessa forma, quando o aplicativo ficar offline, ele usará seu cache local ao invés de consultar o servidor. Encontrei esta postagem de John Resig, que explica muito bem por que isso não funciona: ejohn.org/blog/offline-events
Pierre Duplouy
Obrigado por essa postagem no blog. Análise detalhada e direta ao ponto. Acho que o que você deseja alcançar é melhor se você consultar algum servidor (talvez o seu) e, em seguida, alternar para o cache local quando houver x número de tempos limite. O que você acha ?
Trefex
Sim, acho que é a melhor opção - dado o estado da arte atual. Espero que todos os navegadores eventualmente sejam capazes de detectar a perda real de conexão por si mesmos: usar navigator.onLine é muito simples e não deveria ser mais complexo. Você não acha?
Pierre Duplouy
3

Encontre o módulo require.js que escrevi para offline.

define(['offline'], function (Offline) {
    //Tested with Chrome and IE11 Latest Versions as of 20140412
    //Offline.js - http://github.hubspot.com/offline/ 
    //Offline.js is a library to automatically alert your users 
    //when they've lost internet connectivity, like Gmail.
    //It captures AJAX requests which were made while the connection 
    //was down, and remakes them when it's back up, so your app 
    //reacts perfectly.

    //It has a number of beautiful themes and requires no configuration.
    //Object that will be exposed to the outside world. (Revealing Module Pattern)

    var OfflineDetector = {};

    //Flag indicating current network status.
    var isOffline = false;

    //Configuration Options for Offline.js
    Offline.options = {
        checks: {
            xhr: {
                //By default Offline.js queries favicon.ico.
                //Change this to hit a service that simply returns a 204.
                url: 'favicon.ico'
            }
        },

        checkOnLoad: true,
        interceptRequests: true,
        reconnect: true,
        requests: true,
        game: false
    };

    //Offline.js raises the 'up' event when it is able to reach
    //the server indicating that connection is up.
    Offline.on('up', function () {
        isOffline = false;
    });

    //Offline.js raises the 'down' event when it is unable to reach
    //the server indicating that connection is down.
    Offline.on('down', function () {
        isOffline = true;
    });

    //Expose Offline.js instance for outside world!
    OfflineDetector.Offline = Offline;

    //OfflineDetector.isOffline() method returns the current status.
    OfflineDetector.isOffline = function () {
        return isOffline;
    };

    //start() method contains functionality to repeatedly
    //invoke check() method of Offline.js.
    //This repeated call helps in detecting the status.
    OfflineDetector.start = function () {
        var checkOfflineStatus = function () {
            Offline.check();
        };
        setInterval(checkOfflineStatus, 3000);
    };

    //Start OfflineDetector
    OfflineDetector.start();
    return OfflineDetector;
});

Por favor, leia esta postagem do blog e deixe-me saber sua opinião. http://zen-and-art-of-programming.blogspot.com/2014/04/html-5-offline-application-development.html Ele contém um exemplo de código usando offline.js para detectar quando o cliente está offline.

Srihari Sridharan
fonte
3
Observe que as respostas somente com link são desencorajadas, as respostas do SO devem ser o ponto final de uma busca por uma solução (em vez de outra parada de referências, que tendem a ficar obsoletas com o tempo). Considere adicionar uma sinopse independente aqui, mantendo o link como uma referência.
kleopatra de
Olá, postei o módulo require.js junto com a referência do link. Obrigado pela sugestão.
Srihari Sridharan
2

você pode detectar o modo cross-browser offline facilmente como abaixo

var randomValue = Math.floor((1 + Math.random()) * 0x10000)

$.ajax({
      type: "HEAD",
      url: "http://yoururl.com?rand=" + randomValue,
      contentType: "application/json",
      error: function(response) { return response.status == 0; },
      success: function() { return true; }
   });

você pode substituir yoururl.com por document.location.pathname.

O ponto crucial da solução é tentar se conectar ao seu nome de domínio, se você não conseguir se conectar - você está offline. funciona em qualquer navegador.

Harishr
fonte
dado que não há nome de url após o nome de domínio, não há alteração de obter 404
harishr
Às vezes não, como a página inicial da minha API é um 404
Ben Aubin
como a home page da sua API é importante ?? não entendi. porque quando chega ao servidor, não há url - portanto, nenhum processamento, mesmo que sua página inicial seja 404 - não importa. pode ser se você puder fornecer algum código de amostra, que eu possa tentar e entender o problema que você está declarando
harishr
Não apenas a minha API, mas muitos sites não têm uma página inicial. Verifique se o código de status e os dados recebidos são nulos, essa é a melhor maneira de ter certeza de que não é apenas um erro normal e esperado
Ben Aubin
meu webapi também não tem uma página inicial, mas o acima ainda funciona. é por isso que estou confuso. como a página inicial é importante, visto que está funcionando
harishr
2

Eu uso a opção FALLBACK no manifesto do cache HTML5 para verificar se meu aplicativo html5 está online ou offline por:

FALLBACK:
/online.txt /offline.txt

Na página html eu uso javascript para ler o conteúdo do arquivo txt online / offline:

<script>$.get( "urlto/online.txt", function( data ) {
$( ".result" ).html( data );
alert( data );
});</script>

Quando estiver offline, o script lerá o conteúdo do offline.txt. Com base no texto dos arquivos, você pode detectar se a página da web está online ou offline.

Marcel Scholte
fonte
0

Aqui está minha solução.

Testado com IE, Opera, Chrome, FireFox, Safari, como Phonegap WebApp no ​​IOS 8 e como Phonegap WebApp no ​​Android 4.4.2

Esta solução não está funcionando com o FireFox no localhost.

========================================================== =================================

onlineCheck.js (caminho de arquivo: "root / js / onlineCheck.js):

var isApp = false;

function onLoad() {
        document.addEventListener("deviceready", onDeviceReady, false);
}

function onDeviceReady() {
    isApp = true;
    }


function isOnlineTest() {
    alert(checkOnline());
}

function isBrowserOnline(no,yes){
    //Didnt work local
    //Need "firefox.php" in root dictionary
    var xhr = XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHttp');
    xhr.onload = function(){
        if(yes instanceof Function){
            yes();
        }
    }
    xhr.onerror = function(){
        if(no instanceof Function){
            no();
        }
    }
    xhr.open("GET","checkOnline.php",true);
    xhr.send();
}

function checkOnline(){

    if(isApp)
    {
        var xhr = new XMLHttpRequest();
        var file = "http://dexheimer.cc/apps/kartei/neu/dot.png";

        try {
            xhr.open('HEAD', file , false); 
            xhr.send(null);

            if (xhr.status >= 200 && xhr.status < 304) {
                return true;
            } else {
                return false;
            }
        } catch (e) 
        {
            return false;
        }
    }else
    {
        var tmpIsOnline = false;

        tmpIsOnline = navigator.onLine;

        if(tmpIsOnline || tmpIsOnline == "undefined")
        {
            try{
                //Didnt work local
                //Need "firefox.php" in root dictionary
                var xhr = XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHttp');
                xhr.onload = function(){
                    tmpIsOnline = true;
                }
                xhr.onerror = function(){
                    tmpIsOnline = false;
                }
                xhr.open("GET","checkOnline.php",false);
                xhr.send();
            }catch (e){
                tmpIsOnline = false;
            }
        }
        return tmpIsOnline;

    }
}

========================================================== =================================

index.html (caminho de arquivo: "root / index.html"):

<!DOCTYPE html>
<html>


<head>
    ...

    <script type="text/javascript" src="js/onlineCheck.js" ></script>

    ...

</head>

...

<body onload="onLoad()">

...

    <div onclick="isOnlineTest()">  
        Online?
    </div>
...
</body>

</html>

========================================================== =================================

checkOnline.php (filepath: "root"):

<?php echo 'true'; ?> 
JoJoWhatsUp
fonte
0

bem, você pode tentar o plugin javascript que pode monitorar a conexão do navegador em tempo real e notificar o usuário se a internet ou a conexão do navegador com a internet caiu.

Plug-in Javascript Wiremonkey e a demonstração que você pode encontrar aqui

http://ryvan-js.github.io/

Ry Van
fonte
0

Usando o corpo do documento:

<body ononline="onlineConditions()" onoffline="offlineConditions()">(...)</body>

Usando o evento Javascript:

window.addEventListener('load', function() {

  function updateOnlineStatus() {

    var condition = navigator.onLine ? "online" : "offline";
    if( condition == 'online' ){
        console.log( 'condition: online')
    }else{
        console.log( 'condition: offline')
    }

  }

  window.addEventListener('online',  updateOnlineStatus );
  window.addEventListener('offline', updateOnlineStatus );

});

Referência :
Document-Body: ononline Event
Javascript-Event: Eventos online e offline

Pensamentos adicionais:
Para distribuir a "conexão de rede não é o mesmo que conexão de internet" Problema com os métodos acima: Você pode verificar a conexão de internet uma vez com ajax no início do aplicativo e configurar um modo online / offline. Crie um botão de reconexão para o usuário ficar online. E adicione em cada solicitação ajax com falha uma função que leve o usuário de volta ao modo offline.

Milingu Kilu
fonte
1
Isso não funcionará: window.addEventListener('online', updateOnlineStatus(event) );porque você está chamando a função updateOnlineStatus () imediatamente. Deveria serwindow.addEventListener('online', updateOnlineStatus );
Sébastien Rosset