Angular2 http重试逻辑
Angular2 http retry logic
我有一个API,它具有基于令牌的身份验证机制。成功登录后,我将两个令牌存储在浏览器的本地存储中——访问和刷新令牌。访问令牌包含在服务器端授权用户所需的所有必要信息,并且具有到期日期。当访问令牌过期时,客户端可以使用刷新令牌请求新的访问令牌,并且在响应中它将获得一对新令牌。
在angular 1.x中,实现非常简单明了。例如,我们可以使用拦截器:
httpInterceptor.$inject = ['$httpProvider'];
function httpInterceptor($httpProvider) {
$httpProvider.interceptors.push(handleStaleAccessToken);
handleStaleAccessToken.$inject = ['$q', '$injector', 'session'];
function handleStaleAccessToken($q, $injector, session) {
function logoutAndRedirect() {
var authenticationRedirect = $injector.get('authenticationRedirect');
session.destroy();
authenticationRedirect.toLoginPage();
}
return {
responseError: function(rejection) {
// Do nothing for non 403 errors
if (rejection.status !== 403) {
return $q.reject(rejection);
}
var errorCode = rejection.data.error && rejection.data.error.code;
if (errorCode === 'access_token_expired') {
var $http = $injector.get('$http');
// Refresh token
var params = { refreshToken: session.getRefreshToken() };
return $http.post('/api/auth/refresh', params).then(function(response) {
session.setTokens(response.data);
// Re try failed http request
return $http(rejection.config);
}).catch(function(error) {
logoutAndRedirect();
return $q.reject(error);
});
} else {
logoutAndRedirect();
}
return $q.reject(rejection);
}
};
}
}
但是如何在angular 2/rxjs应用程序中实现类似的逻辑呢?
这可以在Angular2中通过扩展Http
类和利用flatMap
等可观察运算符透明地完成。
以下是一些示例代码:
if (hasTokenExpired()) {
return this.authService
.refreshAuthenticationObservable()
.flatMap((authenticationResult:AuthenticationResult) => {
if (authenticationResult.IsAuthenticated == true) {
this.authService.setAuthorizationHeader(request.headers);
return this.http.request(url, request);
}
return Observable.throw(initialError);
});
}
此代码必须集成到Http
的自定义子类中:
一种方法可以是扩展HTTP对象以拦截错误:
@Injectable()
export class CustomHttp extends Http {
constructor(backend: ConnectionBackend, defaultOptions: RequestOptions) {
super(backend, defaultOptions);
}
request(url: string | Request, options?: RequestOptionsArgs): Observable<Response> {
console.log('request...');
return super.request(url, options).catch(res => {
// do something
});
}
get(url: string, options?: RequestOptionsArgs): Observable<Response> {
console.log('get...');
return super.get(url, options).catch(res => {
// do something
});
}
}
并按如下所述进行注册:
bootstrap(AppComponent, [HTTP_PROVIDERS,
new Provider(Http, {
useFactory: (backend: XHRBackend, defaultOptions: RequestOptions) => new CustomHttp(backend, defaultOptions),
deps: [XHRBackend, RequestOptions]
})
]);
有关更多详细信息,请查看以下问题:
- 使用rxjs处理刷新令牌
- Angular 2-如何在全球范围内获得Observable.throw
在我最近的项目shafihuzaib/cdp ng样板中,我不得不做一些类似的事情,并找到了这个问题的答案。我无法采用上述建议的解决方案,因为它感觉很复杂,有些不可取。所以在我实现了一个解决方案之后,我回来留下了我的解决方案。然而,不同的是,在我的情况下,我有两个这样的代币。
因此,每个需要检查令牌有效性的请求都会在该函数中调用。
tokenValidatedRequest(func): Observable<any>{
let returnObservable = new Observable();
/**
* 1. check for auth token expiry - refresh it, if necessary
*/
if( parseInt(localStorage.getItem('AUTH_TOKEN_EXPIRY')) < (new Date()).valueOf() ){
//auth expired
this.refresh().subscribe(res => {
//refreshed
//this.postAuthSuccess(res);
returnObservable = func();
})
}
else{
//auth not expired
returnObservable = func();
}
return returnObservable;
}
这里最重要的是func()
应该返回一个Observable
,这样它就可以相应地被消耗。
makeSomeHttpCall(){
this.tokenValidatedRequest(()=>{
return this.http.post(...);
}). subscribe();
}
对于一个新人来说,这可能看起来有点复杂,但我相信它会更有效率。
在以下链接中,请忽略与此问题无关的细节,并专注于建议解决方案的使用。
tokenValidatedRequest()
在我的项目中的实际实施。
tokenValidatedRequest(func , tqlCheck = false): Observable<any>{
/**
* Delegate the actual task. However return an Observable, so as to execute
* the callback function only when subscribed to..
*/
//return Observable.create(obs => obs = (this.__tokenValidatedRequest(func, tqlCheck)));
return this.__tokenValidatedRequest(func, tqlCheck);
}
private __tokenValidatedRequest(func, tqlCheck = false): Observable<any>{
let returnObservable = new Observable();
/**
* 1. check for auth token expiry - refresh it, if necessary
* 2. after step 1 - check for TQL token expiry (if tqlCheck is true) - refresh it, if necessary
* 3.
*/
if( parseInt(localStorage.getItem('AUTH_TOKEN_EXPIRY')) < (new Date()).valueOf() ){
//auth expired
this.refresh().subscribe(res => {
//refreshed
this.postAuthSuccess(res);
if(tqlCheck && localStorage.getItem("TQL_TOKEN_EXPIRY") &&
parseInt(localStorage.getItem("TQL_TOKEN_EXPIRY")) < (new Date()).valueOf()
){
this.activateUser().subscribe(res => {
//TQL token subscribed
returnObservable = func();
})
}
else{
// Probably not a TQL request
returnObservable = func();
}
})
}
else{
//auth not expired
//check if tql token has expired
if(tqlCheck && localStorage.getItem("TQL_TOKEN_EXPIRY") &&
parseInt(localStorage.getItem("TQL_TOKEN_EXPIRY")) < (new Date()).valueOf()
){
this.activateUser().subscribe(res => {
//TQL token subscribed
returnObservable = func();
})
}
else{
// Probably not a TQL request or none of the tokens expired
returnObservable = func();
}
}
return returnObservable;
}
它是如何在其他服务中使用的!
getAllParkingSpaces() : Observable<any> {
let query = {
Query: {
....
}
};
return this.authService.tokenValidatedRequest(()=>{
return this.api.post( CONFIG.api.engineUrl + 'devices/parking', query);
}, true);
}
我终于订阅了!
this.realTimeParkingService.getAllParkingSpaces().subscribe( r => {
this.parkingSpaces = r;
});
相关文章:
- JavaScript:在源404上重试
- 用分隔符分隔具有多个整数值的字符串的Javascript"重试错误的值
- Ajax在NodeJS中为一个耗时的请求请求多次重试
- 如何仅在RxJs中可观察到的源发出的特定错误上重试
- BreezeJS中央错误处理程序和自动重试
- 如何捕获请求中的错误,然后打开模态,然后在模态使用RxJS关闭时重试
- Angular2 http重试逻辑
- JS重试函数几次,看看它是否返回true
- Promise中的递归重试
- Bluebird Promise 重试 DocumentDB 请求
- 如果发生错误,如何重试 DriveApp.getFileById,直到成功
- Nodejs - 让客户端套接字在 5 秒超时后重试
- 重试时更改 ajax 数据
- RxJS 重试运算符与 ajax 调用
- JS/JQuery 重试 1 秒后 img 加载
- JavaScript重试承诺,直到解决
- 服务器发送的事件忽略重试
- 如果错误可重试,请重试异步函数
- Meteor-如何在不丢失上下文的情况下重试失败的HTTP请求
- 如何流式传输http响应到文件,在503上重试