Как обнаружить онлайн / офлайн кроссбраузер событий?

Я пытаюсь точно определить, когда браузер отключается, используя HTML5 онлайн и автономные события.

Вот мой код:

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

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

Он отлично работает, когда я просто нажимаю "Работать в автономном режиме" на Firefox или IE, но это вроде случайная работа, когда я на самом деле отключаю провод.

Какой лучший способ обнаружить это изменение? Я хотел бы избежать повторения вызовов ajax с таймаутами.

16 ответов

Решение

Поставщики браузеров не могут договориться о том, как определить автономный режим. Некоторые браузеры имеют функцию "Работа в автономном режиме", которую они рассматривают отдельно от отсутствия доступа к сети, что опять-таки отличается от доступа в Интернет. Все это беспорядок. Некоторые поставщики браузеров обновляют флаг navigator.onLine, когда фактический доступ к сети теряется, другие нет.

Из спецификации:

Возвращает false, если пользовательский агент определенно находится в автономном режиме (отключен от сети). Возвращает true, если пользовательский агент может быть в сети.

События онлайн и оффлайн запускаются, когда значение этого атрибута изменяется.

Атрибут navigator.onLine должен возвращать false, если пользовательский агент не будет связываться с сетью, когда пользователь переходит по ссылкам или когда скрипт запрашивает удаленную страницу (или знает, что такая попытка потерпит неудачу), и должен возвращать true в противном случае.

Наконец, спецификация отмечает:

Этот атрибут по своей сути ненадежен. Компьютер может быть подключен к сети без доступа к Интернету.

Основные поставщики браузеров отличаются тем, что означает "автономный".

Chrome и Safari автоматически определят, когда вы переходите в автономный режим, а это означает, что события и свойства в режиме онлайн будут срабатывать автоматически при отключении сетевого кабеля.

Firefox (Mozilla), Opera и IE используют другой подход и считают вас "онлайн", если вы явно не выберете "Автономный режим" в браузере - даже если у вас нет работающего сетевого подключения.

Есть допустимые аргументы для поведения Firefox/Mozilla, которые изложены в комментариях к этому сообщению об ошибке:

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

Но, чтобы ответить на вопрос - вы не можете полагаться на онлайн / офлайн события / свойство, чтобы определить, действительно ли существует сетевое подключение.

Вместо этого вы должны использовать альтернативные подходы.

Раздел "Примечания" этой статьи для разработчиков Mozilla содержит ссылки на два альтернативных метода:

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

"Если API не реализован в браузере, вы можете использовать другие сигналы для обнаружения, если вы не в сети, включая прослушивание событий ошибок AppCache и ответов от XMLHttpRequest"

Это ссылка на пример подхода "прослушивание событий ошибки AppCache":

http://www.html5rocks.com/en/mobile/workingoffthegrid/

... и пример подхода "прослушивание сбоев XMLHttpRequest":

http://www.html5rocks.com/en/mobile/workingoffthegrid/

HTH, - Чад

Сегодня есть библиотека JavaScript с открытым исходным кодом, которая выполняет эту работу: она называется Offline.js,

Автоматически отображать онлайн / оффлайн индикацию для ваших пользователей.

https://github.com/HubSpot/offline

Не забудьте проверить полную README. Он содержит события, которые вы можете подключить.

Вот тестовая страница. Это красиво / имеет приятный интерфейс обратной связи, кстати!:)

Offline.js Simulate UI - это плагин Offline.js, который позволяет вам проверять, как ваши страницы реагируют на различные состояния подключения, без необходимости использовать методы перебора, чтобы отключить фактическое подключение.

Лучший способ, который работает сейчас на всех основных браузерах, это следующий скрипт:

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

Источник: http://robertnyman.com/html5/offline/online-offline-events.html

С недавнего времени navigator.onLine показывает то же самое во всех основных браузерах, и, следовательно, может использоваться.

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

Самыми старыми версиями, которые правильно поддерживают это, являются: Firefox 41, IE 9, Chrome 14 и Safari 5.

В настоящее время это будет представлять почти весь спектр пользователей, но вы всегда должны проверять возможности пользователей вашей страницы.

До FF 41 это было бы только показать false если пользователь вручную перевел браузер в автономный режим. В IE 8 свойство было на body, вместо window,

источник: caniuse

window.navigator.onLine Атрибут и связанные с ним события в настоящее время ненадежны в определенных веб-браузерах ( особенно на рабочем столе Firefox), как сказал @Junto, поэтому я написал небольшую функцию (используя jQuery), которая периодически проверяет состояние сетевого подключения и поднимает соответствующий offline а также online событие:

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

Вы можете использовать это так:

// Hack to use the checkNetwork() function only on Firefox 
// (http://stackru.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
}

Для прослушивания оффлайн и онлайн событий (с помощью jQuery):

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

navigator.onLine - беспорядок

Я сталкиваюсь с этим, когда пытаюсь сделать AJAX-вызов на сервер.

Существует несколько возможных ситуаций, когда клиент находится в автономном режиме:

  • тайм-аут вызова ajax и вы получаете ошибку
  • вызов ajax возвращает успех, но сообщение является нулевым
  • вызов ajax не выполняется, потому что браузер решает так (возможно, это происходит, когда navigator.onLine через некоторое время становится ложным)

Решение, которое я использую, состоит в том, чтобы контролировать статус самостоятельно с помощью JavaScript. Я устанавливаю условие успешного вызова, в любом другом случае я предполагаю, что клиент находится в автономном режиме. Что-то вроде этого:

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

В HTML5 вы можете использовать navigator.onLine имущество. Смотри сюда:

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

Вероятно, ваше текущее поведение является случайным, так как javascript только подготавливает переменную "browser", а затем знает, если вы находитесь в автономном режиме и в сети, но он фактически не проверяет сетевое соединение.

Дайте нам знать, если это то, что вы ищете.

С уважением,

Вы можете легко обнаружить кросс-браузерный способ, как показано ниже

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

Вы можете заменить yoururl.com на document.location.pathname,

Суть решения в том, попробуйте подключиться к вашему доменному имени, если вы не можете подключиться - вы находитесь в автономном режиме. работает кросс-браузер.

Пожалуйста, найдите модуль require.js, который я написал для 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;
});

Пожалуйста, прочитайте этот блог и дайте мне знать ваши мысли. http://zen-and-art-of-programming.blogspot.com/2014/04/html-5-offline-application-development.html Содержит пример кода с использованием offline.js для определения, когда клиент находится в автономном режиме.

Я использую опцию FALLBACK в манифесте кэша HTML5, чтобы проверить, подключено ли мое html5-приложение к сети:

FALLBACK:
/online.txt /offline.txt

На html-странице я использую javascript для чтения содержимого онлайн / оффлайн текстового файла:

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

В автономном режиме скрипт будет читать содержимое файла offline.txt. Основываясь на тексте в файлах, вы можете определить, находится ли веб-страница в автономном режиме.

Используя тело документа:

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

Использование события Javascript:

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

  function updateOnlineStatus(event) {

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

  }

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

});

Ссылка:
Тело документа: он- лайн событие
Javascript-Event: онлайн и оффлайн события

Дополнительные мысли:
Отгрузить "сетевое соединение не то же самое, что интернет-соединение" Проблема из вышеперечисленных способов: Вы можете проверить интернет-соединение один раз с помощью ajax при запуске приложения и настроить режим онлайн / офлайн. Создайте кнопку переподключения, чтобы пользователь мог выходить в интернет. И добавляйте в каждый неудачный запрос ajax функцию, которая возвращает пользователя в автономный режим.

Вот мое решение.

Протестировано с IE, Opera, Chrome, FireFox, Safari, как Phonegap WebApp на IOS 8 и как Phonegap WebApp на Android 4.4.2

Это решение не работает с FireFox на localhost.

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

onlineCheck.js (путь к файлу: "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 (filepath: "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'; ?> 
      <html>
<head>
<script>
     window.addEventListener("online",function(){
    document.getElementById('note').
    innerHTML='you are online';
    });
    window.addEventListener("offline",function(){
    document.getElementById('note').
    innerHTML='you are offline';
    });
</script>
</head>
<body>
   <div id="note"> </div>
</body>
</html>

Хорошо, вы можете попробовать плагин javascript, который может контролировать соединение с браузером в режиме реального времени и уведомляет пользователя, если интернет или соединение браузеров с интернетом оборвалось.

Плагин Wiremonkey Javascript и демо вы можете найти здесь

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

Вы пробовали использовать сервисных работников? http://www.html5rocks.com/en/tutorials/service-worker/introduction/

Другие вопросы по тегам