我正在使用 Angular 6 中的HttpInterceptor
,并尝试构建刷新令牌机制:
当 httpClient 请求获取401
状态代码(未经授权(时,HttpInterceptor
将创建一个将刷新令牌的请求,它将更新第一个请求的标头并使用新令牌再次调用它。
代码一直有效,直到我需要使用从刷新令牌请求获取的新令牌再次调用原始请求的阶段。 这是我的代码:
export class MyInterceptor implements HttpInterceptor {
constructor(public restService:RestService){}
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
return next.handle(request).pipe(
tap(event => {
if (event instanceof HttpResponse) {
console.log('succeed');
}
}, error => {
if(error.status==401){
this.restService.refreshToken().subscribe(response => {
this.restService.updateHeaders(response['token']);
const newRequest = request.clone();
return next.handle(newRequest);
});
}
})
)
}
}
你需要做如下的事情。您还需要确保将新标头附加到请求中。不确定你在哪里做,因为它不在这个拦截器中。附加它的最佳部分是在拦截器中。即使是这个,以防您实际上在服务中这样做。
// if multiple requests fail, do only one refresh request
private readonly refreshToken$ = this.restService
.refreshToken() //the refresh token method could update the token in it's internal state, not sure why the later call to updateHeaders
.pipe(
tap(response => this.restService.updateHeaders(response['token'])),
ignoreElements(),
shareReplay(1)
);
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
return next
.handle(request)
.pipe(
catchError(error => {
if (error.status === 401) {
return concat(this.refreshToken$, throwError(new RetryRequestError()));
} else {
throw error;
}
}),
retryWhen(error => {
if (error instanceof RetryRequestError) {
// try the request again
return;
}
throw error;
})
);
}
class RetryRequestError extends Error {
constructor() {
super('retry_request');
Object.setPrototypeOf(this, RetryRequestError.prototype);
}
}
我阅读了更多关于它的信息,并使用了某人编写的代码,我对其进行了一点更改并修改了它,最终它对我有用。 当然,如果有人使用此代码,他应该修改它。
import { Observable } from 'rxjs';
import { HttpClient } from '@angular/common/http';
import { catchError, switchMap } from 'rxjs/operators';
import { Injectable } from "@angular/core";
import { HttpInterceptor, HttpRequest, HttpHandler, HttpSentEvent, HttpHeaderResponse, HttpProgressEvent, HttpResponse, HttpUserEvent, HttpErrorResponse } from "@angular/common/http";
import { _throw as observableThrowError } from 'rxjs/observable/throw';
import { Router } from "@angular/router";
import { environment } from '../../../environments/environment'
@Injectable()
export class RequestInterceptorService implements HttpInterceptor {
public endPoints;
constructor(public httpClient: HttpClient, public router: Router) { this.endPoints = environment.endPoints; }
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpSentEvent | HttpHeaderResponse | HttpProgressEvent | HttpResponse<any> | HttpUserEvent<any>> {
return <any>next.handle(req.clone({ headers: req.headers.set('Cache-Control', 'no-cache').set('Pragma', 'no-cache'), withCredentials: true })).pipe(
catchError(error => {
if (req.url.indexOf('refresh_token_login') != -1 && ((<HttpErrorResponse>error).status) == 401) {//the app created request for getting new token/session and got 401,meaning the refresh token/session also expired
this.router.navigate(['/logout']);
}
else if (((<HttpErrorResponse>error).status) == 401 && (<HttpErrorResponse>error).error.error_code == 401001) { // 401001 meaning that the token is invalid
this.router.navigate(['/logout']);
}
else if (((<HttpErrorResponse>error).status) == 401 && (<HttpErrorResponse>error).error.error_code == 401002) { // 401002 meaning that the token has expired
return this.handle401Error(req, next);
} else {
return observableThrowError(error.error);
}
}));
}
handle401Error(req: HttpRequest<any>, next: HttpHandler) {
return this.refreshToken().pipe(
switchMap((res) => {
if (res.status == 200) {
return next.handle(this.getNewRequest(req));
}else{
return this.logoutUser();
}
}),
catchError(error => {
return next.handle(this.getNewRequest(req));
})
)
}
getNewRequest(req: HttpRequest<any>): HttpRequest<any> {
return req.clone({ headers: req.headers.set('Cache-Control', 'no-cache').set('Pragma', 'no-cache'), withCredentials: true });
}
logoutUser() {
this.router.navigate(['/logout']);
return observableThrowError("");
}
refreshToken() {
return this.httpClient.get(this.endPoints.refreshToken, { observe: 'response' }).pipe(
catchError(error => {
return observableThrowError(error);
}));
}
}