使用 $http 拦截器重试失败的请求
Retry failed requests with $http interceptor
与我的网络应用程序通信的 API 有时会超载,如果它无法处理请求,则会发送 500 内部服务器错误。
我的 Web 应用程序可以发送 100 多个不同的请求,因此如果我对每个请求分别实施重试,我将花费数小时的时间进行输入。
我已经在使用 $httpProvider 拦截器,这里是(简化版)
$httpProvider.interceptors.push(function ($q) {
return {
responseError: function (response) {
switch (response.status) {
case 401 :
window.location = "/";
alert('Session has expired. Redirecting to login page');
break;
case 500 :
// TODO: retry the request
break;
}
return $q.reject(response);
}
};
});
服务器收到500响应码后如何重新发送请求?
Angular 提供对 $http 服务用于在响应中执行请求的配置对象的引用(response.config)。这意味着如果我们可以在拦截器中注入 $http 服务,我们就可以轻松地重新发送请求。由于循环依赖,无法在拦截器中简单地注入 $http 服务,但幸运的是有一个解决方法。
这是一个如何实现此类拦截器的示例。
$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.
您可以通过稍微扩展状态代码检查来检查任何可能的服务器端错误。此拦截器将尝试多次重试请求,并将对任何 500 或更高的响应代码执行此操作。等待1秒后重试,尝试3次后放弃
$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);
}
};
});
我也想在我的 response
块中重试请求,因此结合来自 SO 的不同帖子的多个答案,我编写了如下拦截器 -
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 &
与我的网络应用程序通信的 API 有时会超载,如果它无法处理请求,则会发送 500 内部服务器错误。
我的 Web 应用程序可以发送 100 多个不同的请求,因此如果我对每个请求分别实施重试,我将花费数小时的时间进行输入。
我已经在使用 $httpProvider 拦截器,这里是(简化版)
$httpProvider.interceptors.push(function ($q) {
return {
responseError: function (response) {
switch (response.status) {
case 401 :
window.location = "/";
alert('Session has expired. Redirecting to login page');
break;
case 500 :
// TODO: retry the request
break;
}
return $q.reject(response);
}
};
});
服务器收到500响应码后如何重新发送请求?
Angular 提供对 $http 服务用于在响应中执行请求的配置对象的引用(response.config)。这意味着如果我们可以在拦截器中注入 $http 服务,我们就可以轻松地重新发送请求。由于循环依赖,无法在拦截器中简单地注入 $http 服务,但幸运的是有一个解决方法。
这是一个如何实现此类拦截器的示例。
$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.
您可以通过稍微扩展状态代码检查来检查任何可能的服务器端错误。此拦截器将尝试多次重试请求,并将对任何 500 或更高的响应代码执行此操作。等待1秒后重试,尝试3次后放弃
$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);
}
};
});
我也想在我的 response
块中重试请求,因此结合来自 SO 的不同帖子的多个答案,我编写了如下拦截器 -
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 &