离子检查互联网连接

时间:2017-09-06 18:12:00

标签: angular ionic-framework

我正在寻找一种解决方案来检测移动设备真正在线并连接到互联网。

我显然在http拦截器中尝试了以下方法:

if (navigator.connection.type != Connection.NONE) alert("you're online!")

问题在于连接到没有互联网的wifi网络的用户会收到“你在线”的消息,尽管他们没有互联网。为什么?因为在这种情况下我们有navigator.connection.type = Connection.WIFI。

有关解决方案的任何帮助吗?

我显然可以ping谷歌,但这不是那么优雅,不确定谷歌会欣赏我超载他们的服务器。

我还想过捕获所有失败的http请求的响应,但不确定是否基于此我可以断定用户是否有互联网或者请求因其他原因而失败。

4 个答案:

答案 0 :(得分:0)

您可以ping一个类似网站的服务器,然后检查您是否收到任何回复 互联网连接不是

答案 1 :(得分:0)

您可以对在服务器端创建的端点进行Get调用,该端点只响应200状态且没有数据。 如果检测到navigator.connection.type的更改,我只会这样做。 对于其余部分,我建议在您进行的每个请求上实现错误回调函数,以便您可以处理意外的连接丢失或200和201以外的任何其他内容。

答案 2 :(得分:0)

您可以添加EventListener,无论用户是Online还是Offline

您需要在run函数中添加平台就绪,如下所示:

$ionicPlatform.ready(function(){
 document.addEventListener("offline", offlineCallBackFunction, false);
 document.addEventListener("online", onlineCallBackFunction, false);

})

您的回调功能如下:

  function offlineCallBackFunction() {
          $ionicPopup.alert({
                title: "Internet Disconnected",
                content: "Internet is disconnected on your device."
            });

        }

    function onlineCallBackFunction() {
        $ionicPopup.alert({
            title: "Internet Connected",
            content: "Internet is connected on your device."
        })
        .then(function (result) {
            window.location.reload();
        });
    }

<强>更新

以上方法检测到您是否在网络上,但是您可以通过调用自己的Server (API)网址来检查您是否有互联网访问权限。

不要使用不属于实际请求的主机进行测试,特别是如果它是您无法控制的主机。也就是说,如果您想测试用户是否可以访问www.example.com,请不要ping www.google.com。您的尝试可能被视为恶意攻击,特别是如果您的应用程序变得流行。

答案 3 :(得分:0)

正如@David所述,没有系统事件可以告诉您是否真的有可用的互联网连接。

逻辑

创建一个布尔值vm.isInternetUp并假设用户已连接。用户可以断开连接有三个原因:

  1. 如果浏览器触发了离线事件,则表示没有wifi,3g或以太网连接
  2. 如果设备连接到wifi频道,但wifi频道没有互联网。
  3. 可能还有没有互联网的3G /以太网连接,但这与我们的情况无关(不包括在这篇文章中)。
  4. 现在我们只需要检测其中一个条件何时发生,从而将vm.isInternetUp变为false。当该标志变为离线时,我们将启动一个带有http请求的循环到我们的API,直到我们得到肯定的响应。

    这非常麻烦,但通过这种方式,我们不会通过连续的http请求超载我们的服务器以检查互联网连接的状态。当用户重新上线时,只有一个http会到达服务器。

    代码

    有不同的方法可以实现这一点(请查看@ webruster对在线/离线事件的回答)。我选择使用拦截器,因为它最符合我的特定需求。

      vm.isInternetUp = true //assume internet is up at startup
      var interceptor = {
        request: function(config) {
          return vm.checkForInternet(config);
        },
        responseError: function(reject){
          return vm.handleBadWifi(reject)
        }
      }
    

    由于原因1,我使用角度的http request interceptor来检查我们是否已连接到wifi。如果没有,则表示我们已离线。

      vm.checkForInternet = function(config) {
    
        if (angular.isUndefined(window.Connection)) {
          // The project is run in a web browser so window.Connection doesn’t exist. Assume we have internet.
          console.log("window.Connection doesn't exist")
          return config;
        }
        //if there is no internet
        if (navigator.connection.type === Connection.NONE || !vm.isInternetUp) {
          vm.isInternetUp = false
          vm.reconnect();
          }
          else {
            console.log("connected but bad wifi")
          }
        }
        return config;
      }
    

    由于原因2,我使用$ http responseError interceptor拦截所有http请求。正如文档所述,reject.status = -1 usually means the request was aborted;我们从中得出结论,没有互联网连接。

      vm.handleBadWifi = function(reject) {
          if (navigator.connection.type == Connection.WIFI && reject.status == -1) {
            vm.isInternetUp = false
            vm.checkForInternet(); //this will launch reconnection loop until connected again
          }  
          return $q.reject(reject);      
      }
    

    最后,一旦我们得到肯定请求,重新连接循环就会停止。它已经很长了,因为我们不能使用有角度的$ http服务,因为我们在$ http拦截器中。使用$ http会导致循环依赖。

      vm.reconnect = function() {
        //Restart only if we were previously disconnected and after checking that we really have the internet
        if (!vm.isInternetUp & !vm.reconnecting) {
          console.log("attempting http call")
          vm.reconnecting = true;
          //backend-host is only pinged if internet was previously disconnected. In this way it does not overload the server.
          //we don't use $http because that would induce a circular dependency (we're in an $http interceptor here). As this is a pure js http call this request will not be intercepted.
          pureJsHttpGet(backendHost + 'projects/',vm.reconnectSuccess,vm.reconnectError)
        }           
      }
      vm.reconnectSuccess = function () {
        vm.isInternetUp = true;
        vm.reconnecting = false;  
      }
      vm.reconnectError = function (error) {
        $timeout(function () {
          vm.reconnecting = false;
          vm.checkForInternet();
        },3000)
        console.error("Did not manage to find an internet connection. Retrying in 3 sec", error)  
        if (navigator.connection.type === Connection.WIFI){
          //create a fake reject error so that the wifi errorhandler knows the request failed
          var reject = {status:-1}
          vm.handleBadWifi(reject)     
        }
      }
      function pureJsHttpGet(theUrl, successCallback, errorCallback){
          var xmlHttp = new XMLHttpRequest();
          xmlHttp.onreadystatechange = function() { 
              if (xmlHttp.readyState == 4 && xmlHttp.status == 200) 
                successCallback(xmlHttp.responseText);
              else if (xmlHttp.readyState == 4 && xmlHttp.status == 0)
                errorCallback(xmlHttp)
          }
          xmlHttp.open("GET", theUrl, true); // true for asynchronous 
          xmlHttp.send(null);
      }