正如@大衛表示,沒有系統事件會告訴你,如果你真的有一個工作的互聯網連接。
邏輯
創建布爾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