正如@大卫表示,没有系统事件会告诉你,如果你真的有一个工作的互联网连接。
逻辑
创建布尔vm.isInternetUp
并假定用户连接。有三个原因,用户可以断开连接:
- 如果脱机事件是由浏览器发射,这意味着没有WIFI,3G或以太网连接
- 如果将设备连接到WiFi信道,但无线频道没有互联网。
- 也可能有一个没有互联网的3G /以太网连接,但这与我们的案例不相关(未包含在本文中)。
现在我们只需要检测何时发生这些情况之一,即vm.isInternetUp
为false。当该标志转为脱机状态时,我们开始一个带有http请求的循环,直到我们获得肯定的响应。
这很麻烦,但这样我们就不会用连续的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拦截器那样使用angular的$ 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);
}
如果您正在使用火力地堡,他们必须要检查用户的连接(我使用,似乎是工作的罚款这)一个非常有用的方式。除此之外,还有[this](https://stackoverflow.com/a/16242703/7468384)关于检查与Angular的连接的问题和答案。 –
那么没有系统事件会告诉你,如果你_really_有_working_连接。除了尝试一个设置,比如说超时3000ms,没有别的。您可以使用e GET调用服务器上的某个虚拟资源,或者像您说的那样ping谷歌 - 我认为它们可以处理您的流量:) – David