使用$http拦截器重试请求

Retry request with $http interceptor

本文关键字:重试 请求 http 使用      更新时间:2023-09-26

我相信有一种简单的方法可以做我想做的事情,我只是无法理解它。如果请求失败,我如何让http拦截器处于angular状态来重试请求?我想我必须在请求中做出某种承诺,对吧?然后在响应中,我必须检查响应是否是错误的,如果是,是否承诺?这是怎么做到的?我一直在尝试调整这里的示例:http://docs.angularjs.org/api/ng.$http

我尝试使用拦截器的原因是,我需要向请求url添加令牌和其他一些东西,以及一些处理xdr的东西。

这里有一个$http拦截器,它(立即)重放超时的请求(即响应状态0)。构建这个例子有两个不明显的元素(对我来说!):

  1. 如何从拦截器中调用$http——简单地将$http添加到依赖项列表中是不起作用的,因为angular抱怨循环依赖项
  2. 如何引用响应对象的原始请求以重试

这个答案解决了这两个主题,但涉及更多,所以我在下面包含了一个简化版本。

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

在实际实现中,您可能需要更复杂的http响应代码处理、重试次数的限制等。

为了完整起见,这里有一个带有重试延迟的mygzi答案版本:

.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返回一个promise,该promise由函数参数返回的内容完成,因此我们可以方便地返回封装在$timeout中的$http调用。

我为之前编写的一个应用程序做过这件事。要进行重试,请将$http用法封装在函数中(最好是在服务中,以便您可以轻松地重用它)。如果请求失败,请再次调用该函数。

诀窍是将promise对象与每个请求一起传递。如果你为每个请求创建一个新的promise,那么它将与你返回给原始调用者的promise不匹配,所以一旦请求通过,原始调用者就不会得到他的promise解析。

所以它是这样的(注意,在每次重试中都会传递defer对象):

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