Обработка ошибок $ http: выделение пользователя в автономном режиме от других ошибок

У меня есть простая контактная форма, которую Angular отправляет через AJAX в мое приложение на Google App Engine. (Обработчик POST использует функцию send_mail , чтобы отправить электронное письмо владельцу сайта) , Это код клиента:

$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.');
});

Очевидно, что alert() обрабатывает все ошибки. Предполагая, что в моем серверном коде нет ошибок, я полагаю, что вероятность того, что App Engine вернет что-либо, кроме кода состояния HTTP 200, невелика. Однако я все же хотел бы различать ошибки сервера и пользователя, потерявшего соединение.

Я думал об использовании textStatus XMLHttpRequest в соответствии с этот ответ SO , но он не доступен для обратного вызова $http.error(). Я также подумал об использовании Offline.js , но мне не нужно большинство из того, что это так, что в данном случае это выглядит как потраченные впустую байты.

$http.error() status я получаю когда офлайн равен 0, но я не уверен, насколько надежным будет кросс-браузер. Что я должен использовать?

7 голосов | спросил KnewB 12 FriEurope/Moscow2014-12-12T22:57:32+03:00Europe/Moscow12bEurope/MoscowFri, 12 Dec 2014 22:57:32 +0300 2014, 22:57:32

3 ответа


0

Перед тем, как дать вам решение, я просто хотел осветить проблемы с предоставленным браузером флагом is-offline

  1. Автономный флаг другого браузера имеет различное значение

    а. для некоторых браузеров это означает, что интернета нет

    б. для некоторых браузеров это означает, что интранет отсутствует

    с. некоторые браузеры допускают автономный режим, поэтому, даже если нет Интернета, вы фактически не находитесь в автономном режиме.

  2. не все браузеры согласованно поддерживают автономный режим

Еще одна проблема, с которой я столкнулся при использовании флага на основе браузера, - это сценарий разработки, при котором наличие Интернета не требуется, и это не должно вызывать автономный режим (для меня я блокирую все взаимодействие с пользователем, если мой сайт отключается). Вы можете решить эту проблему, используя другой индикатор, сообщающий, что вы находитесь в dev /prod и т. Д.

И самая важная часть, почему мы хотим выяснить, находится ли браузер в автономном режиме, заключается в том, что мы заботимся только о том, доступен ли наш веб-сайт или нет, нам на самом деле все равно, есть ли Интернет или нет. Так что даже если браузер скажет нам, что он не в сети, это не совсем то, что мы хотим. есть небольшая разница между тем, что мы хотим, и тем, что предоставляет браузер.

Итак, учитывая все вышесказанное, я решил проблему с помощью автономной директивы, которую я использую для блокировки взаимодействия с пользователем, если пользователь находится в автономном режиме

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,
    };
}]);

Я собирался использовать offline.js, это было слишком много, и большинство из них мне не нужно, так что это решение, которое я придумал, чисто в angular.js.

обратите внимание, что во время этих вызовов вызывается http-перехватчик, я хотел этого избежать, поэтому я использовал $ .ajax для вызовов

        $.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;
            }
        }
        );

вы можете заменить логику внутри isOnline true /false любой пользовательской логикой, которую вы хотите.

ответил harishr 16 TueEurope/Moscow2014-12-16T14:02:35+03:00Europe/Moscow12bEurope/MoscowTue, 16 Dec 2014 14:02:35 +0300 2014, 14:02:35
0

Я бы пошел с проверкой response.status === 0. Я протестировал его с помощью приведенного ниже кода (его необходимо поместить на веб-сервер, который можно включать /выключать по желанию), и я получаю 0 в текущих версиях Google Chrome, Mozilla Firefox и Internet Explorer. Вы можете использовать его для тестирования всех браузеров, которые хотите поддерживать.


Код для проверки состояния соединения:

<!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>
ответил hon2a 22 MonEurope/Moscow2014-12-22T14:15:11+03:00Europe/Moscow12bEurope/MoscowMon, 22 Dec 2014 14:15:11 +0300 2014, 14:15:11
0

попробуйте это

$http.post('', jQuery.param(user), {
    headers: {
        'Content-Type': 'application/x-www-form-urlencoded'
    }
}).complete(function(data, status, headers, config) {
    //...                        
});
ответил Mohammad Nurdin 20 SatEurope/Moscow2014-12-20T11:46:58+03:00Europe/Moscow12bEurope/MoscowSat, 20 Dec 2014 11:46:58 +0300 2014, 11:46:58

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132