如何检测在线/离线事件跨浏览器?


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

谢谢你的建议。所以您会推荐Ajax方法吗?即。继续发送XHR呼叫超时?
皮埃尔·杜普洛伊

Firefox(以及IE和Opera)的实现是错误的。请在此处查看对此的评论:bugzilla.mozilla.org/show_bug.cgi?
id=654579#c9

4
您可能想查看Offline.js,这是为此目的而构建的开源库。
亚当

Answers:


70

浏览器供应商无法就如何离线定义达成一致。某些浏览器具有“脱机工作”功能,他们认为这与缺少网络访问权限是分开的,这又不同于Internet访问。整个事情一团糟。当实际的网络访问丢失时,某些浏览器供应商会更新navigator.onLine标志,而其他浏览器供应商不会。

从规格:

如果用户代理肯定处于脱机状态(与网络断开连接),则返回false。如果用户代理可能在线,则返回true。

当此属性的值更改时,将触发联机和脱机事件。

如果当用户跟随​​链接或脚本请求远程页面(或知道这样的尝试将失败)时用户代理将不与网络联系,则navigator.onLine属性必须返回false,否则必须返回true。

最后,规格说明:

此属性本质上是不可靠的。可以在没有Internet访问的情况下将计算机连接到网络。


23
连接断开后,只有Chrome才能正确设置navigator.onLine。如果您删除互联网连接,Safari和Firefox都不会将标志设置为false。
chovy 2011年

2
@chovy,现在呢?我最近测试了它在Firefox / Chrome和得到预期的结果,看到该标志被设定,当我打开和关闭了互联网连接..
詹姆斯卡泽塔

12
今天1/31/2017,我打开了OSX Chrome 55.0.2883.95,Safari 10.0.3和FF 50.1.0。当我留在网络上但从路由器上拔掉了电线时,所有的window.navigator.onLine似乎都工作良好。他们都正确地离线检测。
nycynik '17

3
所有主要浏览器都支持navigator.onLine(并且已经使用了一段时间):caniuse.com/#feat=online-status
RafaelLüder18年

@RafaelLüder到今天为止是正确的,但此答案写于2011年1月!
丽贝卡

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/zh-CN/mobile/workingoffthegrid/#toc-appcache

...以及“侦听XMLHttpRequest故障”方法的示例:

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

HTH-乍得


1
从Firefox 41开始:(updates this property when the OS reports a change in network connectivity on Windows, Linux, and OS X.根据您提到的文档)。因此,如果您使用“离线模式”浏览器进行浏览,不仅会处于离线状态
哥们,2017年

17

今天,有一个开放源代码的JavaScript库可以完成这项工作:称为Offline.js

自动向您的用户显示在线/离线指示。

https://github.com/HubSpot/offline

确保检查完整的自述文件。它包含可以挂接到的事件。

这是一个测试页。顺便说一句,它很漂亮/有一个不错的反馈用户界面!:)

Offline.js Simulate UI是一个Offline.js插件,使用它可以测试页面如何响应不同的连接状态,而不必使用蛮力方法来禁用实际的连接。


2
该库实际上是通过在引擎盖下重复获取本地图标来工作的。我认为该库太大,功能太多。主要技巧是重复获取favicon。
卡雷尔·比列克(KarelBílek),2016年

1
拔下网络电缆时无法检测到脱机状态
豪华的

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


3
正如代码本身明确规定的意见-它工作在Firefox / Chrome浏览器,如果你拔掉网络线或打开wifi关闭。
Manish 2014年

我尝试访问“源”链接并断开以太网电缆,它在IE中显示为“您处于离线状态”,但在Firefox / Chrome浏览器中却没有(使用所有浏览器的最新版本)。可能是我缺少什么吗?
Manish 2014年

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

资料来源:


11

window.navigator.onLine属性及其相关的事件都在某些Web浏览器(目前不可靠尤其是Firefox的桌面)作为@Junto说,所以我写了(使用jQuery)能够定期检查网络连接状态,并提高相应的一个小功能offlineonline事件:

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

7

navigator.onLine一片混乱

尝试对服务器进行Ajax调用时,我会遇到此问题。

客户端脱机时有几种可能的情况:

  • ajax调用超时,您收到错误
  • ajax调用返回成功,但msg为空
  • 不会执行ajax调用,因为浏览器决定这样做(可能是当navigator.onLine在一段时间后变为false时)

我正在使用的解决方案是使用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。我更改了代码,现在仅检查了navigator.onLine属性,但是得到的行为与以前相同。请查看mattbasta的评论。
皮埃尔·杜普洛伊

嗨,Pedro,我同意mattbasta的观点,但是我希望它对您有用:)我肯定会使用Ajax方法查询一些您一直知道的URL,然后您会知道连接是否丢失。另外,为什么您需要准确检测在线/离线状态?也许我们想知道更多,那么您的问题将有另一种解决方案。让我们知道
Trefex

1
好的,谢谢:)我只是认为,如果应用程序能够自动检测到连接的变化(无需在FF或IE中手动启用脱机模式),则对用户会更好。这样,当应用程序脱机时,它将使用其本地缓存而不是查询服务器。我从约翰·雷西格(John Resig)找到了这篇文章,这在很大程度上解释了为什么它不起作用:ejohn.org/blog/offline-events
Pierre Duplouy,2010年

感谢您的博客文章。完全深入分析并指出重点。我认为,如果要查询某个服务器(也许是您自己的服务器),然后在超时次数为x时切换到本地缓存,那么您想要实现的目标是最好的。你怎么看 ?
Trefex

是的,鉴于当前的最新水平,我认为这是最好的选择。我希望所有浏览器最终都能自己检测到实际的连接丢失:使用navigator.onLine非常简单,并且应该不会更复杂。你不觉得吗
Pierre Duplouy,2010年

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 2014年

嗨,我已经发布了require.js模块以及链接参考。谢谢你的建议。
Srihari Sridharan 2014年

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

解决方案的关键是,如果无法连接,请尝试连接到您的域名-您处于脱机状态。跨浏览器工作。


鉴于域名之后没有网址名称,获取404的内容没有变化
harishr 2015年

有时不,例如我的api主页是404
Ben Aubin

您的api主页有什么关系?没有得到它。因为当它到达服务器时,没有url-即使您的主页是404,也没有处理-没关系。可能是您是否可以提供一些示例代码,我可以尝试并理解您所说明的问题
harishr 2015年

不仅是我的api,许多网站都没有主页。检查以确保收到的状态代码和数据为空,这是确保它不仅是正常的,可预期的错误的最佳方法
Ben Aubin

我的webapi也没有主页,但是以上仍然有效。这就是为什么我感到困惑。考虑到首页的工作
原理,首页的重要性

2

我通过以下方式在HTML5缓存清单中使用FALLBACK选项来检查我的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等IE,IOS 8上作为Phonegap WebApp和在Android 4.4.2上作为Phonegap WebApp进行了测试

此解决方案不适用于localhost上的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(文件路径:“ root”):

<?php echo 'true'; ?> 


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

});

参考
文档正文
在线事件 Javascript事件:在线和离线事件

附加提示:
绕过“网络连接与Internet连接不同”上述方法的问题:您可以在应用程序启动时用ajax检查一次Internet连接,并配置在线/离线模式。创建一个重新连接按钮供用户上线。并在每个失败的ajax请求上添加一个功能,该功能可将用户踢回脱机模式。


1
这将不起作用:window.addEventListener('online', updateOnlineStatus(event) );因为您正在立即调用updateOnlineStatus()函数。它应该是window.addEventListener('online', updateOnlineStatus );
塞巴斯蒂安·罗塞特
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.