14

我的 webapp 正在与之交谈的 API 有时会过载,如果它无法处理请求,则会发送 500 Internal Server Error。

我的 Web 应用程序可以发送 100 多个不同的请求,因此如果我对每个请求单独实施重试,我将花费数小时的打字时间。

我已经在使用 $httpProvider 拦截器了,这里是(简化的)

$httpProvider.interceptors.push(function ($q) {
    return {
        responseError: function (response) {
            switch (response.status) {
                case 401 :
                    window.location = "/";
                    alert('Session has expired. Redirecting to login page');
                    break;
                case 500 :
                    // TODO: retry the request
                    break;
            }
            return $q.reject(response);
        }
    };
});

从服务器收到 500 响应码后如何重新发送请求?

4

3 回答 3

20

Angular 提供对$http服务用于在响应(response.config)中执行请求的配置对象的引用。这意味着如果我们可以在拦截器中注入$http服务,我们就可以轻松地重新发送请求。由于循环依赖,不可能在拦截器中简单地注入$http服务,但幸运的是,有一个解决方法。

这是一个如何实现这种拦截器的示例。

$httpProvider.interceptors.push(function ($q, $injector) {
    var incrementalTimeout = 1000;

    function retryRequest (httpConfig) {
        var $timeout = $injector.get('$timeout');
        var thisTimeout = incrementalTimeout;
        incrementalTimeout *= 2;
        return $timeout(function() {
            var $http = $injector.get('$http');
            return $http(httpConfig);
        }, thisTimeout);
    };

    return {
        responseError: function (response) {
            if (response.status === 500) {
                if (incrementalTimeout < 5000) {
                    return retryRequest(response.config);
                }
                else {
                    alert('The remote server seems to be busy at the moment. Please try again in 5 minutes');
                }
            }
            else {
                incrementalTimeout = 1000;
            }
            return $q.reject(response);
        }
    };
});

注意:在此示例实现中,拦截器将重试请求,直到您收到状态不同于500的响应。对此的改进可以是在重试和仅重试一次之前添加一些超时。

于 2015-09-19T11:07:07.493 回答
3

您可以通过进一步扩展状态代码检查来检查任何可能的服务器端错误。此拦截器将尝试多次重试请求,并将在任何响应代码为 500 或更高的情况下这样做。它会在重试前等待 1 秒,并在 3 次尝试后放弃。

$httpProvider.interceptors.push(function ($q, $injector) {

    var retries = 0,
        waitBetweenErrors = 1000,
        maxRetries = 3;

    function onResponseError(httpConfig) {
        var $http = $injector.get('$http');
        setTimeout(function () {
            return $http(httpConfig);
        }, waitBetweenErrors);
    }

    return {
        responseError: function (response) {
            if (response.status >= 500 && retries < maxRetries) {
                retries++;
                return onResponseError(response.config);
            }
            retries = 0;
            return $q.reject(response);
        }
    };
});
于 2015-09-19T23:11:54.577 回答
0

我也想在我的response块中重试请求,因此结合来自 SO 不同帖子的多个答案,我编写了我的拦截器,如下所示 -

app.config(['$httpProvider', function ($httpProvider) {
    $httpProvider.interceptors.push(['$rootScope', '$cookies', '$q', '$injector', function ($rootScope, $cookies, $q, $injector) {
        var retries = 0, maxRetries = 3;

        return {
            request: function (config) {
                var csrf = $cookies.get("CSRF-Token");
                config.headers['X-CSRF-Token'] = csrf;
                if (config.data) config.data['CSRF-Token'] = csrf;
                return config;
            },
            response: function (r) {
                if (r.data.rCode == "000") {
                    $rootScope.serviceError = true;
                    if (retries < maxRetries) {
                        retries++;
                        var $http = $injector.get('$http');
                        return $http(r.config);
                    } else {
                        console.log('The remote server seems to be busy at the moment. Please try again in 5 minutes');
                    }
                }
                return r;
            },
            responseError: function (r) {
                if (r.status === 500) {
                    if (retries < maxRetries) {
                        retries++;
                        var $http = $injector.get('$http');
                        return $http(r.config);
                    } else {
                        console.log('The remote server seems to be busy at the moment. Please try again in 5 minutes');
                    }
                }

                retries = 0;
                return $q.reject(r);
            }
        }
    }]);
}])

归功于@S.Klechkovski、@Cameron 和https://stackoverflow.com/a/20915196/5729813

于 2020-06-05T11:30:55.147 回答