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

Posted

技术标签:

【中文标题】如何检测在线/离线事件跨浏览器?【英文标题】:How to detect online/offline event cross-browser? 【发布时间】:2011-03-11 23:58:36 【问题描述】:

我正在尝试使用 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 调用。

【问题讨论】:

我同意 Trefex 的观点,但我还想补充一点,对于大多数应用程序来说,连接检测支持充其量只是粗制滥造:仅仅因为拔掉电线并不会立即构成连接丢失。依靠一种不物理测试连接是否打开的方法并不能真正保证准确的结果。 感谢您的建议。所以你会推荐Ajax方法吗? IE。继续发送超时的 XHR 调用? Firefox(以及 IE 和 Opera)的实现是错误的。在此处查看我对此的评论:bugzilla.mozilla.org/show_bug.cgi?id=654579#c9 您可能想查看Offline.js,这是一个专门为此目的而构建的开源库。 【参考方案1】:

正如@Junto 所说,window.navigator.onLine 属性及其相关事件目前在某些 Web 浏览器 (especially Firefox desktop) 上不可靠,因此我编写了一个小函数(使用 jQuery)定期检查网络连接状态并引发适当的offlineonline 事件:

// Global variable somewhere in your app to replicate the 
// window.navigator.onLine variable (this last 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://***.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');
  
);

【讨论】:

【参考方案2】:

目前在 2011 年,各个浏览器供应商无法就如何定义离线达成一致。一些浏览器具有离线工作功能,他们认为这与缺乏网络访问是分开的,这又与互联网访问不同。整个事情是一团糟。一些浏览器供应商会在实际网络访问丢失时更新 navigator.onLine 标志,而其他浏览器供应商则不会。

来自规范:

如果用户代理是,则返回 false 绝对离线(断开连接 网络)。如果用户返回 true 代理可能在线。

线上线下活动分别是 当此属性的值触发时 变化。

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

最后,规范说明:

这个属性是天生的 不可靠。一台电脑可以 连接到网络而无需 上网。

【讨论】:

只有 Chrome 才能在连接断开时正确设置 navigator.onLine。如果您删除互联网连接,Safari 和 Firefox 都不会将该标志设置为 false。 @chovy 现在怎么样?我最近在 Firefox/Chrome 中对其进行了测试并得到了预期的结果,看到标志正在设置,当我关闭并打开互联网连接时.. 今天 1/31/2017 我打开了 OSX Chrome 55.0.2883.95、Safari 10.0.3 和 FF 50.1.0。当我留在我的网络上时,所有的 window.navigator.onLine 似乎都工作得很好,但是从我的路由器上取下了电源线。他们都正确检测到离线。 navigator.onLine 被所有主流浏览器支持(并且已经有一段时间了):caniuse.com/#feat=online-status @RafaelLüder 截至今天正确,但这个答案是在 2011 年 1 月写的!【参考方案3】:

主要浏览器供应商对“离线”的含义有所不同。

Chrome、Safari 和 Firefox(从版本 41 起)会自动检测您何时“离线” - 这意味着当您拔下网络电缆时“在线”事件和属性将自动触发。

Mozilla Firefox(41 版之前)、Opera 和 IE 采用不同的方法,除非您在浏览器中明确选择“离线模式”,否则会将您视为“在线”——即使您没有可用的网络连接。

对于 Firefox/Mozilla 行为有一些有效的参数,这些参数在此错误报告的 cmets 中进行了概述:

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, -- 乍得

【讨论】:

从 Firefox 41 开始:updates this property when the OS reports a change in network connectivity on Windows, Linux, and OS X.(根据您提到的文档)。因此,如果您使用浏览器“离线模式”浏览,它不仅会离线【参考方案4】:

使用文档正文:

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

);

参考: 文档正文:ononline Event javascript 事件:Online and offline events

其他想法: 解决“网络连接与互联网连接不同”的问题 上述方法的问题:您可以在应用程序启动时使用 ajax 检查一次互联网连接并配置在线/离线模式。为用户上线创建一个重新连接按钮。并在每个失败的 ajax 请求上添加一个功能,将用户踢回离线模式。

【讨论】:

这不起作用:window.addEventListener('online', updateOnlineStatus(event) ); 因为您正在立即调用 updateOnlineStatus() 函数。应该是window.addEventListener('online', updateOnlineStatus );【参考方案5】:

好吧,你可以试试javascript插件,它可以实时监控浏览器连接,如果互联网或浏览器与互联网的连接出现故障,会通知用户。

Wiremonkey Javascript plugin 以及您可以在此处找到的演示

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

【讨论】:

【参考方案6】:

最近以来,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

【讨论】:

【参考方案7】:

我使用 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 的内容。 根据文件中的文本,您可以检测网页是在线还是离线。

【讨论】:

【参考方案8】:

您可以像下面这样轻松检测离线跨浏览器方式

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

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

【讨论】:

有时不,比如我的api的主页是404 不只是我的api,很多网站都没有主页。检查以确保收到的状态代码和数据为空,这是确保它不仅仅是正常的、可预期的错误的最佳方法 @penne12 我用过这个答案,它也在我的 web-api 中工作 它可以工作,但会带来意想不到的后果,正如我所解释的(错误意味着错误或不在 200 中的错误,有时服务器也会关闭) 如果服务器宕机了,那么我们就下线了,这就是我们要在这里检测的,对吧【参考方案9】:

请找到我为离线编写的 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 来检测客户端何时离线。

【讨论】:

【参考方案10】:

这是我的解决方案。

在 IE、Opera、Chrome、FireFox、Safari 上测试,作为 ios 8 上的 Phonegap WebApp 和 android 4.4.2 上的 Phonegap WebApp

此解决方案不适用于本地主机上的 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'; ?> 

【讨论】:

【参考方案11】:

今天有一个开源 JavaScript 库可以完成这项工作:它被称为 Offline.js

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

https://github.com/HubSpot/offline

请务必查看完整的README。它包含您可以挂钩的事件。

这是test page。顺便说一句,它很漂亮/有一个很好的反馈 UI! :)

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

【讨论】:

该库实际上是通过在后台反复获取本地网站图标来工作的。在我看来,这个库太“大”了,功能太多了;主要技巧就是反复获取网站图标。 拔网线时检测不到离线【参考方案12】:

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

【讨论】:

【参考方案13】:

目前适用于所有主要浏览器的最佳方式是以下脚本:

(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

【讨论】:

正如代码中的 cmets 明确指出的那样 - 如果您拔下以太网电缆或关闭 wifi,它在 Firefox/Chrome 中不起作用 我尝试访问“源”链接并断开以太网电缆,它在 IE 中显示“您处于离线状态”,但在 Firefox/Chrome 中却没有(使用所有浏览器的最新版本)。可能是我遗漏了什么吗?【参考方案14】:

在 HTML5 中,您可以使用 navigator.onLine 属性。看这里:

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

您当前的行为可能是随机的,因为 javascript 仅准备好“浏览器”变量,然后知道您是离线还是在线,但它实际上并没有检查网络连接。

如果这就是您要找的,请告诉我们。

亲切的问候,

【讨论】:

感谢您的帮助 Trefex。我更改了代码,现在只检查 navigator.onLine 属性,但是我得到了与以前相同的行为。请看一下 mattbasta 的评论。 嗨 Pedro,我同意 mattbasta 的观点,但我希望它对你有用 :) 我肯定会使用 Ajax 方法来查询一些你知道的 URL,然后你会知道如果连接是否丢失。另一方面,为什么需要准确检测在线/离线状态?也许如果我们知道更多,您的问题会有另一种解决方案。让我们知道, 好的,谢谢 :) 我只是认为如果应用程序能够自动检测连接的变化对用户来说会更好(无需在 FF 或 IE 中手动启用离线模式)。这样,当应用程序离线时,它将使用其本地缓存而不是查询服务器。我从 John Resig 找到了这篇文章,这几乎解释了为什么这不起作用:ejohn.org/blog/offline-events 感谢您的博文。依靠深入的分析,切中要害。我认为如果您查询某个服务器(可能是您自己的),然后在有 x 次超时时切换到本地缓存,那么您想要实现的效果最好。你怎么看? 是的,我想这是最好的选择——考虑到当前的技术水平。我希望所有浏览器最终都能够自己检测到实际的连接丢失:使用 navigator.onLine 非常简单,这不应该更复杂。你不觉得吗?

以上是关于如何检测在线/离线事件跨浏览器?的主要内容,如果未能解决你的问题,请参考以下文章

谷歌浏览器离线在线同步所有数据以及跨浏览器同步数据

JavaScript 在粘贴事件中获取剪贴板数据(跨浏览器)

检测 Iframe 内容何时加载(跨浏览器)

跨浏览器事件对象封装

JavaScript在粘贴事件上获取剪贴板数据(跨浏览器)

如何在线保存/加载数据(使用 AJAX 和 JSON 存储数据)和离线(本地)