Comment détecter un cross-browser d'événements en ligne / hors ligne?


111

J'essaie de détecter avec précision quand le navigateur se déconnecte, en utilisant les événements HTML5 en ligne et hors ligne.

Voici mon code:

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

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

Cela fonctionne bien lorsque je viens de cliquer sur "Travailler hors ligne" sur Firefox ou IE, mais cela fonctionne de manière aléatoire lorsque je débranche le câble.

Quelle est la meilleure façon de détecter ce changement? Je voudrais éviter de répéter les appels ajax avec des délais d'attente.


2
Je suis d'accord avec Trefex, mais je voudrais également ajouter que la prise en charge de la détection de connexion est au mieux de mauvaise qualité pour la plupart des applications: le simple fait que le fil soit débranché ne constitue pas immédiatement une connexion perdue. S'appuyer sur une méthode qui ne teste pas physiquement si la connexion est ouverte ne peut pas vraiment garantir des résultats précis.
mattbasta

Merci pour vos conseils. Alors, vous recommanderiez la méthode Ajax? c'est à dire. continuer à envoyer des appels XHR avec des délais d'attente?
Pierre Duplouy

L'implémentation de Firefox (et IE et Opera) est erronée. Voir mon commentaire à cet effet ici: bugzilla.mozilla.org/show_bug.cgi?id=654579#c9
thewoolleyman

4
Vous voudrez peut-être consulter Offline.js , une bibliothèque open-source créée à cet effet.
Adam

Réponses:


70

Les fournisseurs de navigateurs ne peuvent pas s'entendre sur la façon de définir hors ligne. Certains navigateurs ont une fonctionnalité de travail hors ligne, qu'ils considèrent comme distincte d'un manque d'accès au réseau, ce qui est encore une fois différent de l'accès à Internet. Le tout est un gâchis. Certains fournisseurs de navigateurs mettent à jour l'indicateur navigator.onLine lorsque l'accès réel au réseau est perdu, d'autres non.

De la spécification:

Renvoie false si l'agent utilisateur est définitivement hors ligne (déconnecté du réseau). Renvoie true si l'agent utilisateur est peut-être en ligne.

Les événements en ligne et hors ligne sont déclenchés lorsque la valeur de cet attribut change.

L'attribut navigator.onLine doit retourner false si l'agent utilisateur ne contactera pas le réseau lorsque l'utilisateur suit des liens ou lorsqu'un script demande une page distante (ou sait qu'une telle tentative échouerait), et doit renvoyer true dans le cas contraire.

Enfin, la spécification note:

Cet attribut est intrinsèquement peu fiable. Un ordinateur peut être connecté à un réseau sans avoir accès à Internet.


23
Seul Chrome définit correctement navigator.onLine lorsque la connectivité est perdue. Safari et Firefox ne définissent jamais l'indicateur sur false si vous supprimez la connexion Internet.
chovy

2
@chovy et que diriez-vous maintenant? Je l'ai récemment testé dans Firefox / Chrome et j'ai obtenu les résultats escomptés, voyant que le drapeau est en cours de définition, lorsque
j'éteins et rallume

12
Aujourd'hui, le 31/01/2017, j'ai ouvert OSX Chrome 55.0.2883.95, Safari 10.0.3 et FF 50.1.0. Tout le window.navigator.onLine semble fonctionner très bien lorsque je suis resté sur mon réseau, mais que j'ai retiré le cordon de mon routeur. Ils ont tous correctement détectés hors ligne.
nycynik le

3
navigator.onLine est pris en charge sur tous les principaux navigateurs (et ce depuis un certain temps): caniuse.com/#feat=online-status
Rafael Lüder

@ RafaelLüder Correct à partir d'aujourd'hui, mais cette réponse a été écrite en janvier 2011!
Rebecca

34

Les principaux fournisseurs de navigateurs diffèrent sur ce que signifie «hors ligne».

Chrome et Safari détectent automatiquement lorsque vous passez "hors ligne", ce qui signifie que les événements et propriétés "en ligne" se déclenchent automatiquement lorsque vous débranchez votre câble réseau.

Firefox (Mozilla), Opera et IE adoptent une approche différente et vous considèrent comme "en ligne" à moins que vous ne choisissiez explicitement "Mode hors ligne" dans le navigateur - même si vous ne disposez pas d'une connexion réseau fonctionnelle.

Il existe des arguments valides pour le comportement de Firefox / Mozilla, qui sont décrits dans les commentaires de ce rapport de bogue:

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

Mais, pour répondre à la question, vous ne pouvez pas vous fier aux événements / propriétés en ligne / hors ligne pour détecter s'il existe réellement une connectivité réseau.

Au lieu de cela, vous devez utiliser des approches alternatives.

La section "Notes" de cet article Mozilla Developer fournit des liens vers deux méthodes alternatives:

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

"Si l'API n'est pas implémentée dans le navigateur, vous pouvez utiliser d'autres signaux pour détecter si vous êtes hors ligne, y compris l'écoute des événements d'erreur AppCache et des réponses de XMLHttpRequest"

Ce lien vers un exemple de l'approche «écouter les événements d'erreur AppCache»:

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

... et un exemple de l'approche "écoute des échecs XMLHttpRequest":

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

HTH, - Tchad


1
À partir de Firefox 41: updates this property when the OS reports a change in network connectivity on Windows, Linux, and OS X.(selon les documents que vous avez mentionnés). Donc, ce n'est pas seulement hors ligne si vous naviguez avec le navigateur "Mode hors ligne"
mec

17

Aujourd'hui, il existe une bibliothèque JavaScript open source qui fait ce travail: elle s'appelle Offline.js.

Affichez automatiquement l'indication en ligne / hors ligne à vos utilisateurs.

https://github.com/HubSpot/offline

Assurez-vous de vérifier le README complet . Il contient des événements auxquels vous pouvez vous connecter.

Voici une page de test . C'est beau / a une belle interface utilisateur de retour au fait! :)

Offline.js Simulate UI est un plug-in Offline.js qui vous permet de tester la façon dont vos pages répondent à différents états de connectivité sans avoir à utiliser des méthodes de force brute pour désactiver votre connectivité réelle.


2
La bibliothèque fonctionne en fait en récupérant le favicon local à plusieurs reprises sous le capot. A mon avis, la bibliothèque est trop "grande" et a trop de fonctionnalités; L'astuce principale consiste simplement à récupérer le favicon à plusieurs reprises.
Karel Bílek

1
Ne détecte pas hors ligne lorsque je débranche le câble réseau
chic du

15

La meilleure façon qui fonctionne maintenant sur tous les principaux navigateurs est le script suivant:

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

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


3
Comme les commentaires dans le code lui-même l'indiquent clairement, cela ne fonctionne pas dans Firefox / Chrome si vous débranchez le câble Ethernet ou désactivez le wifi.
Manish

J'ai essayé de visiter le lien "Source" et le câble Ethernet déconnecté, il a montré "Vous êtes hors ligne" dans IE, mais pas dans Firefox / Chrome pour moi (en utilisant la dernière version de tous les navigateurs). Peut-être que je manque quelque chose?
Manish

13

Depuis récemment, navigator.onLinemontre la même chose sur tous les principaux navigateurs, et est donc utilisable.

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

Les versions les plus anciennes qui prennent en charge cela de la bonne manière sont: Firefox 41 , IE 9, Chrome 14 et Safari 5.

Actuellement, cela représentera presque tout le spectre des utilisateurs, mais vous devez toujours vérifier les capacités des utilisateurs de votre page.

Avant FF 41, il n'apparaissait que falsesi l'utilisateur mettait manuellement le navigateur en mode hors ligne. Dans IE 8, la propriété était sur le body, au lieu dewindow .

source: caniuse


11

L' window.navigator.onLineattribut et ses événements associés sont actuellement peu fiables sur certains navigateurs web ( en particulier de bureau Firefox ) comme l'a dit @Junto, j'ai donc écrit une petite fonction ( en utilisant jQuery) qui vérifient périodiquement l'état de la connectivité réseau et augmenter le lieu offlineet l' onlineévénement:

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

Vous pouvez l'utiliser comme ceci:

// 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
}

Pour écouter les événements hors ligne et en ligne (avec l'aide de jQuery):

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

7

navigator.onLine est un gâchis

Je suis confronté à cela en essayant de faire un appel ajax au serveur.

Il existe plusieurs situations possibles lorsque le client est hors ligne:

  • les délais d'appel ajax et vous recevez une erreur
  • l'appel ajax renvoie le succès, mais le msg est nul
  • l'appel ajax n'est pas exécuté car le navigateur le décide (peut-être que c'est lorsque navigator.onLine devient faux après un certain temps)

La solution que j'utilise est de contrôler moi-même le statut avec javascript. J'ai défini la condition d'un appel réussi, dans tous les autres cas, je suppose que le client est hors ligne. Quelque chose comme ça:

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

5

En HTML5, vous pouvez utiliser la navigator.onLinepropriété. Regardez ici:

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

Votre comportement actuel est probablement aléatoire car le javascript ne prépare que la variable "navigateur" et sait ensuite si vous êtes hors ligne et en ligne, mais il ne vérifie pas réellement la connexion réseau.

Faites-nous savoir si c'est ce que vous recherchez.

Sincères amitiés,


Merci pour votre aide Trefex. J'ai changé mon code, et maintenant je ne vérifie que la propriété navigator.onLine, mais j'obtiens le même comportement qu'avant. Veuillez jeter un œil au commentaire de mattbasta.
Pierre Duplouy

Salut Pedro, je suis d'accord avec mattbasta mais j'espérais que cela fonctionnerait pour vous :) J'utiliserais certainement la méthode Ajax pour interroger une URL dont vous savez qu'elle est toujours active et vous saurez alors si une connexion est perdue ou non. Sur une autre note, pourquoi avez-vous besoin d'une détection précise de l'état en ligne / hors ligne? Peut-être que si nous en savons plus, il y aurait une autre solution à votre problème. Faites-nous savoir,
Trefex

1
Ok, merci :) J'ai juste pensé que ce serait mieux pour l'utilisateur si l'application pouvait détecter automatiquement un changement de connectivité (pas besoin d'activer manuellement le mode hors ligne dans FF ou IE). De cette façon, lorsque l'application se déconnecte, elle utilise son cache local au lieu d'interroger le serveur. J'ai trouvé ce post de John Resig, qui explique à peu près pourquoi cela ne fonctionne pas: ejohn.org/blog/offline-events
Pierre Duplouy

Merci pour ce billet de blog. Relly analyse en profondeur et droit au but. Je pense que ce que vous voulez réaliser, c'est mieux si vous interrogez un serveur (peut-être le vôtre), puis passez au cache local lorsqu'il y a x nombre de délais d'attente. Qu'est-ce que tu penses ?
Trefex

Ouais, je suppose que c'est la meilleure option - étant donné l'état actuel de la technique. J'espère que tous les navigateurs pourront éventuellement détecter par eux-mêmes la perte de connexion: utiliser navigator.onLine est assez simple et cela ne devrait pas être plus complexe. Tu ne penses pas?
Pierre Duplouy

3

Veuillez trouver le module require.js que j'ai écrit pour 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;
});

Veuillez lire ce billet de blog et laissez-moi savoir ce que vous pensez. http://zen-and-art-of-programming.blogspot.com/2014/04/html-5-offline-application-development.html Il contient un exemple de code utilisant offline.js pour détecter lorsque le client est hors ligne.


3
Notez que les réponses liées uniquement aux liens sont déconseillées, les réponses SO devraient être le point final d'une recherche de solution (par rapport à une autre escale de références, qui ont tendance à devenir obsolètes avec le temps). Veuillez envisager d'ajouter un synopsis autonome ici, en gardant le lien comme référence.
kleopatra

Salut, j'ai publié le module require.js avec la référence du lien. Merci pour la suggestion.
Srihari Sridharan

2

vous pouvez détecter facilement plusieurs navigateurs hors ligne comme ci-dessous

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

vous pouvez remplacer yoururl.com par document.location.pathname.

Le nœud de la solution est, essayez de vous connecter à votre nom de domaine, si vous ne parvenez pas à vous connecter - vous êtes hors ligne. fonctionne cross browser.


étant donné qu'il n'y a pas de nom d'url après le nom de domaine, il n'y a pas de changement pour obtenir 404
harishr

Parfois non, comme la page d'accueil de mon api est une 404
Ben Aubin

comment la page d'accueil de votre API est-elle importante? ne l'ai pas compris. car quand il arrive sur le serveur, il n'y a pas d'url - donc pas de traitement, même si votre page d'accueil est 404 - cela n'a pas d'importance. peut-être si vous pouvez fournir un exemple de code, que je peux essayer de comprendre le problème que vous
dites

Pas seulement mes API, mais beaucoup de sites n'ont pas de page d'accueil. Assurez-vous que le code d'état et les données reçus sont nuls, c'est la meilleure façon de vous assurer qu'il ne s'agit pas simplement d'une erreur normale et prévisible
Ben Aubin

mon webapi n'a pas non plus de page d'accueil, mais ce qui précède fonctionne toujours. c'est pourquoi je suis confus. comment la page d'accueil compte-t-elle, étant donné qu'elle fonctionne
harishr

2

J'utilise l'option FALLBACK dans le manifeste du cache HTML5 pour vérifier si mon application html5 est en ligne ou hors ligne en:

FALLBACK:
/online.txt /offline.txt

Dans la page html, j'utilise javascript pour lire le contenu du fichier txt en ligne / hors ligne:

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

Lorsqu'il est hors ligne, le script lira le contenu du fichier offline.txt. Sur la base du texte des fichiers, vous pouvez détecter si la page Web est en ligne ou hors ligne.


0

Voici ma solution.

Testé avec IE, Opera, Chrome, FireFox, Safari, comme Phonegap WebApp sur IOS 8 et comme Phonegap WebApp sur Android 4.4.2

Cette solution ne fonctionne pas avec FireFox sur localhost.

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

onlineCheck.js (chemin du fichier: "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 (chemin du fichier: "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 (chemin du fichier: "root"):

<?php echo 'true'; ?> 


0

Utilisation du corps du document:

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

Utilisation de l'événement 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 );

});

Référence :
Document-Body: événement en ligne
Javascript-Event: événements en ligne et hors ligne

Réflexions supplémentaires:
Pour expédier autour de la "connexion réseau n'est pas la même chose que la connexion Internet" Problème des méthodes ci-dessus: Vous pouvez vérifier la connexion Internet une fois avec ajax au démarrage de l'application et configurer un mode en ligne / hors ligne. Créez un bouton de reconnexion pour que l'utilisateur se connecte. Et ajoutez à chaque requête ajax échouée une fonction qui renvoie l'utilisateur en mode hors ligne.


1
Cela ne fonctionnera pas: window.addEventListener('online', updateOnlineStatus(event) );car vous appelez immédiatement la fonction updateOnlineStatus (). Ça devrait êtrewindow.addEventListener('online', updateOnlineStatus );
Sébastien Rosset
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.