检测互联网连接是否离线?

373

我如何在JavaScript中检测互联网连接是否离线?


1
如果您可以或已经使用WebSockets - WebSockets具有必须调用的Close事件,如果用户失去与服务器的连接。 - Simon
2
这让我想起了90年代,当时你只需要声明图像事件,如image = new Image(); image.onload = onloadfunction; image.onerror = onerrorfunction; 然后设置image.src = "image.gif?" + Math.random(); 我认为这种方法今天仍然有效。 - PHP Guru
23个回答

8

我知道这个问题已经有了答案,但我想补充我的看法,说明什么更好,什么不好。

Window.navigator.onLine

我注意到有些答案提到了这个选项,但他们从未提到任何相关的注意事项。

这个选项涉及使用“window.navigator.onLine”,这是现代大多数浏览器中可用的浏览器导航器接口下的一个属性。它真的不是检查互联网可用性的可行选项,因为首先,它是以浏览器为中心,其次,大多数浏览器以不同的方式实现此属性

在Firefox中: 该属性返回一个布尔值,其中true表示联机,false表示脱机,但是这里的注意事项是, “只有当用户跟随链接或脚本请求远程页面时,才会更新该值。” 因此,如果用户处于离线状态并且您从js函数或脚本查询属性,则该属性将始终返回true,直到用户跟随链接。

在Chrome和Safari中: 如果浏览器无法连接到本地区域网络(LAN)或路由器,则它处于脱机状态,所有其他情况都返回true。因此,尽管您可以假设浏览器处于脱机状态时它会返回false值,但您不能假设true值必然意味着浏览器可以访问互联网。您可能会收到错误的阳性,例如在计算机运行虚拟化软件且始终“连接”的虚拟以太网适配器的情况下。

以上声明只是想让您知道仅凭浏览器是不够的。因此,基本上这个选项是不可靠的。

向自己的服务器资源发送请求

  1. 没有100%可靠的服务器可用性,因此如果由于某种原因您的服务器无法访问,将错误地认为用户处于离线状态,而实际上他们已连接到互联网。
  2. 对同一资源的多次请求可能会返回缓存响应,从而使http响应结果不可靠。

如果您同意您的服务器始终在线,那么您可以选择此选项。

以下是一个获取自己资源的简单片段:

// This fetches your website's favicon, so replace path with favicon url
// Notice the appended date param which helps prevent browser caching.
fetch('/favicon.ico?d='+Date.now())
  .then(response => {
    if (!response.ok)
      throw new Error('Network response was not ok');

   // At this point we can safely assume the user has connection to the internet
        console.log("Internet connection available"); 
  })
  .catch(error => {
  // The resource could not be reached
        console.log("No Internet connection", error);
  });

向第三方服务器资源发送请求

这个选项涉及向外部服务器资源发出HTTP请求,如果能够访问则假定已连接到互联网,否则用户处于离线状态。这种方法的主要限制是跨源资源共享(CORS),它会限制访问。大多数信誉良好的网站都会阻止CORS请求,但有些可以尝试。

以下是获取外部资源的简单代码片段,与上面相同,但使用了外部资源的URL:

// Firstly you trigger a resource available from a reputable site
// For demo purpose you can use the favicon from MSN website
// Also notice the appended date param which helps skip browser caching.
fetch('https://static-global-s-msn-com.akamaized.net/hp-neu/sc/2b/a5ea21.ico?d='+Date.now())
  .then(response => {
  // Check if the response is successful
    if (!response.ok)
      throw new Error('Network response was not ok');

// At this point we can safely say the user has connection to the internet
        console.log("Internet available"); 
  })
  .catch(error => {
  // The resource could not be reached
        console.log("No Internet connection", error);
  });

所以,最终我选择了第二个选项作为我的个人项目,该选项涉及请求自己的服务器资源,因为要确定用户设备上是否有“互联网连接”不仅仅是从您的网站容器或受限制的浏览器API中得出结论。

请记住,您的用户也可能处于一些禁止访问某些网站或资源的环境中,这将影响连接性检查的逻辑。最好的方法是:

  • 尝试访问自己服务器上的资源,因为这是您用户的环境(通常我使用网站的favicon因为响应非常轻且不经常更新)。
  • 如果无法连接到资源,请简单地说“连接错误”或“连接丢失”,而不是假定一个广泛的“没有互联网连接”,这取决于许多因素。

7

我需要为一个经常与学校打交道的客户制作一个基于ajax的网页应用程序,这些学校通常的网络连接质量较差。我使用了这个简单的函数来检测是否有网络连接,效果非常好!

我使用CodeIgniter和Jquery:

function checkOnline() {
    setTimeout("doOnlineCheck()", 20000);
}

function doOnlineCheck() {
    //if the server can be reached it returns 1, other wise it times out
    var submitURL = $("#base_path").val() + "index.php/menu/online";

    $.ajax({
        url : submitURL,
        type : "post",
        dataType : "msg",
        timeout : 5000,
        success : function(msg) {
            if(msg==1) {
                $("#online").addClass("online");
                $("#online").removeClass("offline");
            } else {
                $("#online").addClass("offline");
                $("#online").removeClass("online");
            }
            checkOnline();
        },
        error : function() {
            $("#online").addClass("offline");
            $("#online").removeClass("online");
            checkOnline();
        }
    });
}

5
我认为这是一种非常简单的方法。
var x = confirm("Are you sure you want to submit?");
if (x) {
  if (navigator.onLine == true) {
    return true;
  }
  alert('Internet connection is lost');
  return false;
}
return false;

2
在线并不意味着有互联网连接。根据https://developer.mozilla.org/en-US/docs/Web/API/NavigatorOnLine/onLine,如果浏览器无法连接到局域网(LAN)或路由器,则处于离线状态;所有其他情况均返回true。 - Shmuel Kamensky

4

navigator.onLine 这样的一些方法存在与某些浏览器和移动版本不兼容的问题,一个对我有帮助的选择是使用经典的 XMLHttpRequest 方法并预见到可能的情况,即文件存储在缓存中,因此当响应 XMLHttpRequest.status 大于 200 且小于 304 时。

以下是我的代码:

 var xhr = new XMLHttpRequest();
 //index.php is in my web
 xhr.open('HEAD', 'index.php', true);
 xhr.send();

 xhr.addEventListener("readystatechange", processRequest, false);

 function processRequest(e) {
     if (xhr.readyState == 4) {
         //If you use a cache storage manager (service worker), it is likely that the
         //index.php file will be available even without internet, so do the following validation
         if (xhr.status >= 200 && xhr.status < 304) {
             console.log('On line!');
         } else {
             console.log('Offline :(');
         }
     }
}

3
我正在寻找一个客户端解决方案,以检测是否出现了互联网故障或我的服务器不可用。我发现其他解决方案似乎都依赖于第三方脚本文件或图像,这对我来说似乎不能经受时间的考验。外部托管的脚本或图像在未来可能会发生变化,导致检测代码失效。
我已找到一种方法,通过查找带有404代码的xhrStatus来检测它。此外,我使用JSONP绕过CORS限制。除404之外的状态码表示互联网连接不可用。
$.ajax({
    url:      'https://www.bing.com/aJyfYidjSlA' + new Date().getTime() + '.html',
    dataType: 'jsonp',
    timeout:  5000,

    error: function(xhr) {
        if (xhr.status == 404) {
            //internet connection working
        }
        else {
            //internet is down (xhr.status == 0)
        }
    }
});

3
截至2016年10月5日,这个方法已经失效了,不确定原因,只是不想浪费别人的时间。 - Bren
1
我不认为它适用于禁止和错误请求错误 :) - Faisal Naseer

3
如何向谷歌发送一个不带 CORS 的不透明的 HTTP 请求?
    fetch('https://google.com', {
        method: 'GET', // *GET, POST, PUT, DELETE, etc.
        mode: 'no-cors',
    }).then((result) => {
        console.log(result)
    }).catch(e => {
        console.error(e)
    })

设置no-cors的原因是即使在我的电脑上禁用了网络连接,我仍然收到cors错误。所以无论是否有互联网连接,都会收到CORS阻止的消息。添加no-cors可以使请求不透明,这显然似乎可以绕过CORS并允许我简单地检查是否可以连接到Google。

提示:我在此处使用fetch进行http请求。 https://www.npmjs.com/package/fetch


2

我的方式。

<!-- the file named "tt.jpg" should exist in the same directory -->

<script>
function testConnection(callBack)
{
    document.getElementsByTagName('body')[0].innerHTML +=
        '<img id="testImage" style="display: none;" ' +
        'src="tt.jpg?' + Math.random() + '" ' +
        'onerror="testConnectionCallback(false);" ' +
        'onload="testConnectionCallback(true);">';

    testConnectionCallback = function(result){
        callBack(result);

        var element = document.getElementById('testImage');
        element.parentNode.removeChild(element);
    }    
}
</script>

<!-- usage example -->

<script>
function myCallBack(result)
{
    alert(result);
}
</script>

<a href=# onclick=testConnection(myCallBack);>Am I online?</a>

1

如果 navigator.onLinetrue,那么你处于在线状态,否则处于离线状态。


3
这在很大程度上没有用。我从wifi中断或拔掉另一台设备的以太网电缆,尽管实际上不在线,但这个属性仍然为真。我仍然需要进行失败的XHR请求。 - Douglas Gaskell
@DouglasGaskell 哦,我不知道那个,谢谢你纠正我 :) - Karan Tewari
2
@DouglasGaskell 我不同意你所说的。window.navigator.onLine,这个函数可以正常工作。你需要监听 online/offline 事件来查看变化。请参考以下链接:https://medium.com/@JackPu/how-javascript-detect-the-network-status-42f3a6d85f96 或 https://developer.mozilla.org/en-US/docs/Web/API/NavigatorOnLine/onLine。 - phoenisx
2
@phoenisx 我不确定有什么可以反对的?在浏览器中检查此属性,断开互联网连接,然后再次检查。它仍然是真实的。您链接的文档甚至指出“您不能假定真值必然意味着浏览器可以访问互联网。”这基本上总结了它在检测在线/离线状态时的有用性。它还说:“如果浏览器无法连接到本地区域网络(LAN)或路由器,则处于脱机状态”,这再次表明其有用性非常有限。 - Douglas Gaskell
@DouglasGaskell 我完全同意你的观点。如果你想要非常精确地跟踪互联网连接,那么它的使用场景就有限。尽管在大多数情况下,普通用户不会乱动他们的网络驱动程序、浏览器偏好设置或使用虚拟化软件,但在这些情况下,这个值(或事件监听器)是唯一的选择,用于在用户离线时显示一些描述性信息。 - phoenisx
@DouglasGaskell 您先前所述的陈述是当 WiFi 打开或关闭时,该值永远不会变化,但实际上它确实会发生变化。我尚未使用以太网驱动程序进行测试,但我相信它也应该适用。是的,依赖此变量有时可能是无用的,因为对于某些特定情况,该值可能会产生错误的正面结果,如文档中所述,但对于大多数情况,用户正在浏览正常系统(而非虚拟系统),并且他们的网络驱动程序没有缺陷,此值将为 true(除非他们有某些与 ISP 相关的问题)。 - phoenisx

0

您可以尝试这个,如果网络已连接,它将返回true。

function isInternetConnected(){return navigator.onLine;}

0

请求错误中的请求头

$.ajax({
    url: /your_url,
    type: "POST or GET",
    data: your_data,
    success: function(result){
      //do stuff
    },
    error: function(xhr, status, error) {

      //detect if user is online and avoid the use of async
        $.ajax({
            type: "HEAD",
            url: document.location.pathname,
            error: function() { 
              //user is offline, do stuff
              console.log("you are offline"); 
              }
         });
    }   
});

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接