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

111

Я пытаюсь точно определить, когда браузер переходит в автономный режим, используя онлайн-и офлайн-события 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 с таймаутами.

Пьер Дюплуи
источник
2
Я согласен с Trefex, но я также хотел бы добавить, что поддержка обнаружения соединения в лучшем случае некачественная для большинства приложений: просто потому, что провод отключен, не сразу означает потерю соединения. Использование метода, который физически не проверяет, открыто ли соединение, не может гарантировать точных результатов.
mattbasta 06
Спасибо за ваш совет. Так вы бы порекомендовали метод Ajax? т.е. продолжать посылать XHR-вызовы с таймаутом?
Pierre Duplouy 06
Реализация Firefox (а также IE и Opera) неверна. См. Мой комментарий по этому поводу здесь: bugzilla.mozilla.org/show_bug.cgi?id=654579#c9
thewoolleyman
4
Вы можете попробовать Offline.js , библиотеку с открытым исходным кодом , созданную именно для этой цели.
Адам

Ответы:

70

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

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

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

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

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

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

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

Ребекка
источник
23
Только Chrome правильно устанавливает navigator.onLine при потере связи. И Safari, и Firefox никогда не устанавливают флаг в значение false, если вы удаляете подключение к Интернету.
chovy
2
@chovy, а как насчет сейчас? Недавно я протестировал его в Firefox / Chrome и получил ожидаемые результаты, увидев, что флаг устанавливается, когда я выключаю и подключаюсь к Интернету ..
Джеймс Каззетта
12
Сегодня, 31.01.2017, я открыл OSX Chrome 55.0.2883.95, Safari 10.0.3 и FF 50.1.0. Кажется, что все window.navigator.onLine отлично работают, когда я оставался в своей сети, но отключил шнур от моего маршрутизатора. Все они корректно определяются офлайн.
nycynik
3
navigator.onLine поддерживается во всех основных браузерах (и уже некоторое время поддерживается
Rafael Lüder
@ RafaelLüder Верно на сегодняшний день, но этот ответ был написан в январе 2011 года!
Ребекка
34

Основные поставщики браузеров расходятся во мнениях о том, что означает «офлайн».

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/#toc-appcache

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

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

HTH, - Чад

thewoolleyman
источник
1
Начиная с Firefox 41: updates this property when the OS reports a change in network connectivity on Windows, Linux, and OS X.(согласно упомянутым вами документам). Так что это не только в автономном режиме, если вы просматриваете в браузере в «автономном режиме»,
чувак,
17

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

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

https://github.com/HubSpot/offline

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

Вот тестовая страница . Между прочим, это красиво / имеет приятный интерфейс обратной связи! :)

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

Лениэль Маккаферри
источник
2
На самом деле библиотека работает, многократно загружая локальный значок изнутри. На мой взгляд, библиотека слишком «большая» и имеет слишком много функций; основной трюк - это просто многократное получение значка.
Карел Билек
1
Не определяет офлайн, когда я отсоединяю сетевой кабель
poshest
15

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

(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

tmaximini
источник
3
Как ясно сказано в комментариях в самом коде - он не работает в Firefox / Chrome, если вы отключите кабель Ethernet или отключите Wi-Fi.
Manish
Я попытался перейти по ссылке «Источник» и отключил кабель Ethernet, он показал «Вы не в сети» в IE, но не в Firefox / Chrome для меня (с использованием последней версии всех браузеров). Может я что-то упускаю?
Manish
13

С недавнего времени 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

Ароэн Виаене
источник
11

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

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

$(window).bind('online offline', function(e) {
  if (!IS_ONLINE || !window.navigator.onLine) {
    alert('We have a situation here');
  } else {
    alert('Battlestation connected');
  }
});
Epoc
источник
7

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

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

Когда клиент не в сети, возможны несколько ситуаций:

  • таймауты вызова ajax, и вы получаете ошибку
  • вызов ajax возвращает успех, но сообщение равно null
  • вызов 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);
          }
        });
      }
Инструментарий
источник
5

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

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

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

Сообщите нам, если это то, что вы ищете.

С уважением,

Trefex
источник
Спасибо за вашу помощь Trefex. Я изменил свой код и теперь проверяю только свойство navigator.onLine, однако у меня такое же поведение, как и раньше. Пожалуйста, взгляните на комментарий матбасты.
Pierre Duplouy 06
Привет, Педро, я согласен с mattbasta, но я надеялся, что это сработает для вас :) Я бы определенно использовал метод Ajax для запроса некоторого URL-адреса, который, как вы знаете, всегда активен, и тогда вы узнаете, потеряно соединение или нет. С другой стороны, почему вам требуется точное определение статуса онлайн / офлайн? Возможно, если бы мы знали больше, у вашей проблемы было бы другое решение. Сообщите нам,
Trefex 06
1
Хорошо, спасибо :) Я просто подумал, что для пользователя будет лучше, если приложение сможет автоматически определять изменение подключения (нет необходимости вручную включать автономный режим в FF или IE). Таким образом, когда приложение переходит в автономный режим, оно будет использовать свой локальный кеш вместо запросов к серверу. Я нашел этот пост Джона Ресига, который в значительной степени объясняет, почему это не работает: ejohn.org/blog/offline-events
Пьер Дюплуи,
Спасибо за этот пост в блоге. Достаточно глубокого анализа и по делу. Я думаю, что то, что вы хотите достичь, лучше всего, если вы запросите какой-либо сервер (возможно, свой собственный), а затем переключитесь на локальный кеш, когда есть x количество тайм-аутов. Что вы думаете ?
Trefex 06
Да, я думаю, это лучший вариант - учитывая текущее состояние дел. Я надеюсь, что все браузеры в конечном итоге смогут самостоятельно определять фактическую потерю соединения: использовать navigator.onLine довольно просто, и это не должно быть более сложным. Вы так не думаете?
Pierre Duplouy 06
3

Найдите модуль require.js, который я написал для автономного режима.

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 для определения, когда клиент находится в автономном режиме.

Шрихари Шридхаран
источник
3
Обратите внимание, что ответы только на ссылки не приветствуются, ответы SO должны быть конечной точкой поиска решения (по сравнению с еще одной остановкой ссылок, которые со временем устаревают). Пожалуйста, рассмотрите возможность добавления здесь отдельного синопсиса, сохранив ссылку в качестве справочной.
kleopatra
Привет, я разместил модуль require.js вместе со ссылкой. Спасибо за предложение.
Шрихари Шридхаран
2

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

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.

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

Харишр
источник
учитывая, что после имени домена нет URL-
адреса
Иногда нет, например, домашняя страница моего api - 404
Бен Обин
Какое значение имеет домашняя страница api ?? не понял. потому что, когда он попадает на сервер, URL-адрес отсутствует - значит, никакой обработки, даже если ваша домашняя страница - 404 - это не имеет значения. может быть, если вы предоставите образец кода, с помощью которого я могу попытаться понять проблему, о которой вы говорите
harishr
Не только мой api, но и многие сайты не имеют домашней страницы. Убедитесь, что код состояния и полученные данные равны нулю, это лучший способ убедиться, что это не обычная ожидаемая ошибка,
Бен Обин,
у моего webapi тоже нет домашней страницы, но все еще работает. вот почему я запутался. какое значение имеет домашняя страница, учитывая, что она работает
harishr
2

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

FALLBACK:
/online.txt /offline.txt

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

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

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

Марсель Шольте
источник
0

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

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

Это решение не работает с FireFox на локальном хосте.

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

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 (путь к файлу: "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 (путь к файлу: "корень"):

<?php echo 'true'; ?> 
JoJoWhatsUp
источник
0

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

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

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

Ry Van
источник
0

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

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

Использование события 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 );

});

Ссылка :
Document-Body : онлайн- событие
Javascript-Event: онлайн и офлайн-события

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

Милингу Килу
источник
1
Это не сработает: window.addEventListener('online', updateOnlineStatus(event) );потому что вы немедленно вызываете функцию updateOnlineStatus (). Так и должно бытьwindow.addEventListener('online', updateOnlineStatus );
Себастьен Россе