我正在使用Ionic 3和Angular5。
我在实现HTTP拦截器时遇到麻烦,如果HTTP拦截器即将过期,它会刷新我的令牌并发送带有新令牌的下一个请求。问题在于它在发出请求之前不等待刷新令牌更新。我该如何解决?
AuthService
refreshToken(token?: string) {
return this.http.get(`${this.API_URL}/refresh`)
.pipe(catchError(this.handleServerError));
}
TokenInterceptor
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
// If the next request is to my refresh endpoint allow it through
if (URL == `${this.globals.APIURL}/refresh`) {
return request.clone({
setHeaders: {
Authorization: `Bearer ${token}`,
'Accept': 'application/json',
}
});
}
// Else check if token is expiring soon and refresh it and send the new token in the request
else {
const expirationLeft = this.authService.getTokenExpiration();
if (token && expirationLeft < (this.offsetSeconds * 1000) && !this.isUpdating) {
this.isUpdating = true;
try {
this.authService.refreshToken(token)
.subscribe(data =>
{
token = data.token;
this.authService.storeToken(token);
this.authService.authenticationNotifier().next(true);
const clone = request.clone({
setHeaders: {
Authorization: `Bearer ${token}`,
'Accept': 'application/json',
}
});
this.isUpdating = false;
return next.handle(clone);
},
(err) =>
{
this.authService.logout();
this.isUpdating = false;
});
}
catch (e) {
}
}
return request.clone({
setHeaders: {
Authorization: `Bearer ${token}`,
'Accept': 'application/json',
}
});
}
答案 0 :(得分:1)
此代码应完全重写。因为我不知道代码中实际上需要执行哪些操作,所以无法重写它。但是有几件事可以帮助您。首先从拦截而不是请求返回Observable。
return next.handle(req.clone({
setHeaders: {
Authorization: `Bearer ${token}`,
'Accept': 'application/json',
}
}));
在其他情况下
this.updating = true;
return this.authService.refreshToken(token).pipe(
tap(data => {
this.authService.storeToken(token);
this.authService.authenticationNotifier().next(true);
this.isUpdating = false;
}),
mergeMap(data => next.handle(req.clone({
setHeaders: {
Authorization: `Bearer ${data.token}`,
'Accept': 'application/json',
}
}))),
catchError(err => {
this.authService.logout();
this.isUpdating = false;
return of('Error');
})
);
我宁愿将所有refreshToken逻辑移至AuthService。在AuthService中创建一个getToken
方法,该方法返回可观察的包装的令牌,并在其中完成有关token和refreshToken的所有操作。在这种情况下,您在拦截器中需要的所有代码都将是
return this.authService.getToken().pipe(
mergeMap(token=> next.handle(req.clone({
setHeaders: {
Authorization: `Bearer ${token}`,
'Accept': 'application/json',
}
})))
);
没有/没有其他条件,没有多次返回。