$ http错误处理:区分用户脱机与其他错误

Kne*_*ewB 7 ajax google-app-engine angularjs

我有一个简单的联系表单,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.');
});
Run Code Online (Sandbox Code Playgroud)

显然alert()是处理所有错误.假设我的服务器端代码没有错误,我猜测App Engine返回除HTTP状态代码200以外的任何其他内容的可能性很低.但是,我仍然希望区分服务器错误和丢失连接的用户.

我正在考虑textStatus按照这个SO答案使用XMLHttpRequest ,但它似乎不可用于$http.error()回调.我还想过使用Offline.js,但我不需要它做的大部分工作,所以在这种情况下看起来像浪费的字节.

$http.error() status我得到在脱机时为0,但我不知道这是如何跨浏览器的可靠性将是.我该怎么用?

har*_*shr 5

在给你解决方案之前,我只想强调浏览器提供的 is-offline 标志的问题

  1. 不同浏览器的离线标志有不同的含义

    一种。对于某些浏览器,这意味着互联网不存在

    湾 对于某些浏览器,这意味着内部网不存在

    C。某些浏览器确实允许离线模式,因此即使没有互联网,您实际上也不会离线。

  2. 并非所有浏览器都以一致的方式支持离线

我在使用基于浏览器的标志时遇到的另一个问题是开发场景,其中不需要互联网,并且不应该触发离线模式(对我来说,如果我的网站离线,我会阻止所有用户交互)。您可以通过让另一个指示器告诉您您是否处于开发/生产等状态来解决此问题。

最重要的部分,为什么我们关心浏览器是否处于离线模式,因为我们只关心我们的网站是否可以访问,我们实际上并不关心互联网是否存在。所以即使浏览器告诉我们它是离线的,这也不是我们想要的。我们想要的和浏览器提供的有细微的差别。

因此,考虑到以上所有内容,我已经使用离线指令解决了该问题,如果用户离线,我将使用该指令阻止用户交互

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,
    };
}]);
Run Code Online (Sandbox Code Playgroud)

我正要使用 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;
            }
        }
        );
Run Code Online (Sandbox Code Playgroud)

您可以使用您想要的任何自定义逻辑替换 isOnline true/false 中的逻辑。