javascript 使用 $http 拦截器重试请求
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/20075674/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Retry request with $http interceptor
提问by jensengar
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 I would have to build some sort of promise in the request right? Then in the response I would have to check whether the response was an error and if so, do the promise? How is that done? I have been trying to adapt the example here: http://docs.angularjs.org/api/ng.$http
我确信有一种简单的方法可以做我想做的事,我只是无法理解它。如果请求失败,如何以 angular 获取 http 拦截器以重试请求?我想我必须在请求中建立某种承诺,对吗?然后在响应中,我必须检查响应是否是错误,如果是,是否做出承诺?这是怎么做的?我一直在尝试调整这里的例子:http: //docs.angularjs.org/api/ng.$http
The reason I am trying to use an interceptor is because I need to add the token and a few other things to the request url, as well as some things to handle xdr's.
我尝试使用拦截器的原因是我需要将令牌和其他一些内容添加到请求 url 中,以及一些处理 xdr 的内容。
回答by mygzi
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:
这是一个 $http 拦截器,它(立即)重放超时请求(即响应状态 0)。构建这个例子有两个不明显的(对我来说!)元素:
- 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
- How to reference the original request from the response object in order to retry it
- 如何从拦截器中调用 $http - 简单地将 $http 添加到依赖项列表中不起作用,因为 angular 抱怨循环依赖
- 如何从响应对象引用原始请求以重试它
This answeraddresses 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.
在您的实际实现中,您可能需要更复杂的 http 响应代码处理、重试次数限制等。
回答by user1338062
For the sake of completeness, here is a version of mygzi's answerwith retry delay:
为了完整起见,这里有一个带有重试延迟的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
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
.
$timeout
返回一个由函数参数返回的内容完成的承诺,因此我们可以方便地返回$http
包含在$timeout
.
回答by Erik Honn
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.
我已经为我之前编写的应用程序完成了此操作。要进行重试,将 $http 用法包装在一个函数中(或者最好是在一个服务中,以便您可以轻松地重用它)。如果请求失败,则再次调用该函数。
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.
诀窍是将 promise 对象与每个请求一起传递。如果您为每个请求创建一个新的承诺,那么它将与您返回给原始调用者的承诺不匹配,因此一旦请求通过,原始调用者将不会得到他的承诺。
So it is something like this (note that the defer object is passed along in each retry):
所以它是这样的(注意 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;
}
}])