Retry failed requests with $http interceptor

后端 未结 3 582
無奈伤痛
無奈伤痛 2021-02-07 12:20

The API my webapp is talking to sometimes overloads and is sending 500 Internal Server Error if it cannot handle request.

There are 100+ different requests my web applic

相关标签:
3条回答
  • 2021-02-07 13:01

    You can check for any possible server side errors by expanding the status code check a little more. This interceptor will attempt to retry the request multiple times and will do so on any response code 500 or higher. It will wait 1 second before retrying, and give up after 3 tries.

    $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);
            }
        };
    });
    
    0 讨论(0)
  • 2021-02-07 13:11

    Angular provides reference to the config object which was used by $http service for doing the request in the response (response.config). That means if we can inject $http service in the interceptor we can easily resend the request. Simple injecting of $http service in the interceptor is not possible because of the circular dependency but luckily there is a workaround for that.

    This is an example how the implementation of a such interceptor can be done.

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

    Note: In this example implementation the interceptor will retry the request until you receive a response with status that is different than 500. Improvement to this can be adding some timeout before retrying and retrying only once.

    0 讨论(0)
  • 2021-02-07 13:11

    I wanted to retry requests in my response block also, so combining multiple answers from different posts from SO, I've written my interceptor as follows -

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

    credits to @S.Klechkovski, @Cameron & https://stackoverflow.com/a/20915196/5729813

    0 讨论(0)
提交回复
热议问题