2014-12-12 10 views
7

Mam prosty formularz kontaktowy, który Angular przesyła za pośrednictwem AJAX do mojej aplikacji w Google App Engine. (Program obsługi POST używa funkcji send_mail, aby wysłać wiadomość e-mail do właściciela witryny). Jest to kod klienta:Obsługa błędów HTTP: odróżnianie użytkownika offline od innych błędów

$http.post('', jQuery.param(user), { 
    headers: { 
     'Content-Type': 'application/x-www-form-urlencoded' 
    } 
}).success(function(data, status, headers, config) { 
    //...       
}).error(function(data, status, headers, config) { 
    alert('Please check your Internet connection and try again.'); 
}); 

Oczywiście alert() jest obsługa wszystkich błędów. Zakładając, że nie ma błędów w moim kodzie po stronie serwera, domyślam się, że szanse na to, że App Engine zwróci coś innego niż kod statusu HTTP równy 200, jest niski. Jednak nadal chciałbym rozróżnić błędy serwera i użytkownika, który utracił połączenie.

Myślałem o użyciu XMLHttpRequest za textStatus według this SO answer, ale nie wydaje się być dostępne dla wywołania zwrotnego $http.error(). Myślałem także o używaniu Offline.js, ale nie potrzebuję większości tego, co robi, więc wydaje się, że w tym przypadku są to zmarnowane bajty.

The $http.error() Otrzymuję, gdy w trybie offline jest 0, ale nie jestem pewien, jak wieloprzeglądarka stanie się niezawodna. Co powinienem użyć?

+0

O wsparciu: http://caniuse.com/#search=onLine –

+0

Tak, należy sprawdzanie kodów stanu HTTP, ale nie koniecznie dla statusu 0. Sprawdź poprawne zakresy kodów. Zobacz http://stackoverflow.com/questions/23851424/how-to-detect-when-online-offline-status-changes. – user2943490

Odpowiedz

4

Przed daje rozwiązanie Chciałem tylko zwrócić uwagę na problemy z przeglądarką warunkiem jest nieaktywny-flag

  1. nieaktywny flag innej przeglądarki zawiera różnych meanging

    się. w przypadku niektórych przeglądarek oznacza to, że nie ma dostępu do Internetu

    b. w przypadku niektórych przeglądarek oznacza to, że intranet nie istnieje. niektóre przeglądarki dopuszczają tryb offline, więc nawet jeśli nie ma internetu, w rzeczywistości nie jesteś offline.

  2. nie wszystkie przeglądarki obsługują niedostępny w spójny sposób

Kolejny problem miałem z użyciem flagi oparciu przeglądarka jest scenariusz rozwoju, gdzie posiadające internet nie jest to konieczne, a które nie powinny wywołać tryb offline (dla ja blokuję wszelką interakcję z użytkownikiem Jeśli moja witryna przejdzie w tryb offline). Możesz rozwiązać ten problem, dodając inny wskaźnik informujący o tym, czy jesteś w dev/prod, itp.

I najbardziej imp., Dlaczego zależy nam na sprawdzeniu, czy przeglądarka znajduje się w trybie offline, ponieważ dbamy tylko o to, nasza strona internetowa jest osiągalna lub nie, nie obchodzi nas, czy internet jest tam, czy nie. Nawet jeśli przeglądarka mówi nam, że jest offline, nie jest to dokładnie to, czego chcemy. istnieje niewielka różnica między tym, co chcemy, a tym, co zapewnia przeglądarka.

Więc biorąc pod uwagę wszystkie wyżej, mam rozwiązać ten problem przy użyciu dyrektywy offline, który używam do blokowania interakcji użytkownika, jeśli użytkownik nie jest zalogowany

csapp.directive('csOffline', ["$http", '$interval', "$timeout", "$modal", function ($http, $interval, $timeout, $modal) { 
    var linkFn = function (scope) { 

     scope.interval = 10; //seconds 

     var checkConnection = function() { 

      $http({ 
       method: 'HEAD', 
       url: document.location.pathname + "?rand=" + Math.floor((1 + Math.random()) * 0x10000) 
      }) 
       .then(function (response) { 
        $scope.isOnline = true; 
       }).catch(function() { 
        $scope.isOnline = false; 
       }); 
     }; 

     scope.isOnline = true; 

     $interval(checkConnection, scope.interval * 1000); 

     scope.$watch('isOnline', function (newVal) { 
      console.log("isOnline: ", newVal); 
      //custom logic here 
     }); 

    }; 

    return { 
     scope: {}, 
     restrict: 'E', 
     link: linkFn, 
    }; 
}]); 

miałem zamiar użyć offline.js było zbyt dużo i większość z nich nie potrzebowałem, więc jest to rozwiązanie, które wymyśliłem, które jest wyłącznie w angular.js.

należy zauważyć, że przechwytywacz HTTP jest wywoływany podczas tych wywołań, chciałem tego uniknąć, dlatego użyłem $.ajax dla połączeń

 $.ajax({ 
      type: "HEAD", 
      url: document.location.pathname + "?rand=" + Math.floor((1 + Math.random()) * 0x10000), 
      contentType: "application/json", 
      error: function() { 
       scope.isOnline = false; 
      }, 
      success: function (data, textStatus, xhr) { 
       var status = xhr.status; 
       scope.isOnline = status >= 200 && status < 300 || status === 304; 
      } 
     } 
     ); 

można wymienić logikę wewnątrz isOnline prawda/fałsz, ze cokolwiek zwyczaj logiki chcesz.

+0

Przepychanie serwera przez IMHO nie powinno być konieczne, ale myślę, że to jedyny sposób! Potrzebuję go, by był bardziej responsywny, ponieważ to zajmuje mi mniej niż 30 sekund, aby użytkownik mógł wypełnić i przesłać formularz. Jakie byłoby minimalne minimum, aby przejść do '$ interval'? – KnewB

+0

Czy nadwyżka "scope.interval" jest wymagana? – KnewB

+1

sondowanie jest potrzebne, ponieważ każda przeglądarka ma swój własny sposób informowania użytkownika, że ​​jego offline, także dla każdej przeglądarki offline oznacza różne rzeczy, takie jak brak internetu lub brak intranetu, więc lepiej jest mieć implementację opartą na api. [czytaj więcej tutaj] (http://stackoverflow.com/questions/3181080/how-to-detect-online-offline-event-cross-browser) – harishr

-1

próbować ten jeden

$http.post('', jQuery.param(user), { 
    headers: { 
     'Content-Type': 'application/x-www-form-urlencoded' 
    } 
}).complete(function(data, status, headers, config) { 
    //...       
}); 
+0

Niestety nie jestem pewien, co jedziesz pod adresem – KnewB

+0

Nie widzę nigdzie spytanego rozróżniania między trybem offline a innym błędem – Seika85

2

pójdę z response.status === 0 czeku. Przetestowałem go za pomocą poniższego kodu (należy go umieścić na serwerze internetowym, który można dowolnie włączać/wyłączać) i uzyskuję 0 w aktualnych wersjach Google Chrome, Mozilla Firefox i Internet Explorer. Możesz go użyć do przetestowania wszystkich przeglądarek, które chcesz obsłużyć.


Kod stanu połączenia testowania:

<!DOCTYPE html> 
<html> 
    <head> 
     <title>Connection status test</title> 
     <script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.5/angular.min.js"></script> 
     <script type="text/javascript"> 
      var log = [], 
       pendingCount = 0, 
       pendingLimit = 5; 
      angular.module('app', []) 
       .run(function ($rootScope) { 
        $rootScope.log = log; 
       }) 
       .run(function ($http, $interval, $rootScope) { 
        $interval(function() { 
         if (pendingCount >= pendingLimit) { 
          return; 
         } 

         var item = { 
          time: Date.now(), 
          text: 'Pending...' 
         }; 
         ++pendingCount; 
         $http.get('.', {}) 
          .then(function() { 
           item.text = 'Done'; 
          }, function (response) { 
           item.text = 'Done (status ' + response.status + ')'; 
          }) 
          .finally(function() { 
           --pendingCount; 
          }); 
         log.unshift(item); 
        }, 1000); 
       }); 
     </script> 
     <style rel="stylesheet" type="text/css"> 
      ul { 
       list-style: none; 
       padding: 0; 
      } 
     </style> 
    </head> 
    <body ng-app="app"> 
     <ul> 
      <li ng-repeat="item in log">{{item.time | date:'HH:mm:ss'}}: {{item.text}}</li> 
     </ul> 
    </body> 
</html> 
+0

Będę grał z twoim kodem w interesie/do nauki, chociaż niestety myśl o testowaniu w niezliczonej liczbie kombinacji przeglądarek/urządzeń przeraża mnie – KnewB