Retry request with $http interceptor

前端 未结 3 2023
感动是毒
感动是毒 2020-12-05 07:17

I\'m sure there is an easy way to do what I want, I just cant wrap my head around it. How can I get the http interceptor in angular to retry a request if it fails? I imagine

相关标签:
3条回答
  • 2020-12-05 07:20

    For the sake of completeness, here is a version of mygzi's answer with retry delay:

    .factory('httpResponseErrorInterceptor', ['$injector', '$q', '$timeout', function($injector, $q, $timeout) {
      return {
        'responseError': function(response) {
          if (response.status === 0) {
            return $timeout(function() {
              var $http = $injector.get('$http');
              return $http(response.config);
            }, 15000);
          }
          return $q.reject(response);
        }
      };
    }])
    
    .config(function($httpProvider) {
      $httpProvider.interceptors.push('httpResponseErrorInterceptor');
    });
    

    $timeout returns a promise that is completed with what is returned from the function parameter, so we can conveniently just return the $http call wrapped in $timeout.

    0 讨论(0)
  • 2020-12-05 07:21

    Here's a $http interceptor that (immediately) replays timed out request(s) (i.e. response status 0). There were two non-obvious (to me!) elements to constructing this example:

    1. How to call $http from within the interceptor - simply adding $http to the dependency list didn't work as angular complains of a circular dependency
    2. How to reference the original request from the response object in order to retry it

    This answer addresses both topics but is more involved so I include a simplified version below.

    joinApp.factory('httpResponseErrorInterceptor',function($q, $injector) {
      return {
        'responseError': function(response) {
          if (response.status === 0) {
            // should retry
            var $http = $injector.get('$http');
            return $http(response.config);
          }
          // give up
          return $q.reject(response);
        }
      };
    });
    
    joinApp.config(function($httpProvider) {
      $httpProvider.interceptors.push('httpResponseErrorInterceptor');
    });
    

    In your actual implementation, you would likely want more sophisticated http response code processing, a limit to the number of times you retry, etc.

    0 讨论(0)
  • 2020-12-05 07:31

    I've done this for an app I wrote before. To do the retry wrap the $http usage in a function (or preferably in a service so that you can reuse it easily). If the request fails, call the function again.

    The trick is then to pass the promise object along with each request. If you create a new promise with each request then it won't match the one you returned to the original caller, so the original caller won't get his promise resolve once the request passes.

    So it is something like this (note that the defer object is passed along in each retry):

    app.service('HttpService', ['$q', function($q) {
      this.makeRequest = _makeRequest;
    
      function _makeRequest(url, data, deffered) {
        // We want to keep the same promise for each request, so we don't loose track
        if (deferred === undefined) {
          deferred = $q.defer();
        }
    
        // Now make the request
        $http({...}).success(...).error(
          function(){
            // If some condition
            _makeRequest(url, data, deffered);
          }
        )
    
        // Lastly return the promise
        return deferred.promise;
      }
    }])
    
    0 讨论(0)
提交回复
热议问题