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
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.
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:
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.
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
.
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;
}
}])
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With