你的功能请求是否与问题相关?请描述。
当同时进行多个API调用时,当前的拦截器会将所有响应保存在队列中,然后再调用原始请求。
相反,我希望实现类似于流水线请求的功能,即如果一个API调用抛出401或403错误,那么就保持其他请求在请求拦截器中暂停,而不是像当前的做法一样将失败的请求放入队列。
类似这样的功能已经在Angular中使用RxJS实现了。
描述你想要的解决方案
设置一些标志来表示第一个请求已经返回了401或403响应,因此不要调用所有其他API,然后等待其他返回403状态的API,而是采用当前的做法:回调失败的API队列。
如果一个API失败并且正在刷新,则将其他请求保留在请求管道中。
如果设置了刷新令牌,则仅处理该请求。
描述你考虑过的替代方案
- 无响应*
附加上下文/截图
I found similar implementation using RxJs in angular where they pipeline the request when one response fail
import {throwError as observableThrowError, Observable , BehaviorSubject } from 'rxjs';
import {take, filter, catchError, switchMap, finalize} from 'rxjs/operators';
import { Injectable, Injector } from "@angular/core";
import { HttpInterceptor, HttpRequest, HttpHandler, HttpSentEvent, HttpHeaderResponse, HttpProgressEvent, HttpResponse, HttpUserEvent, HttpErrorResponse } from "@angular/common/http";
import { AuthService } from "./auth.service";
@Injectable()
export class RequestInterceptorService implements HttpInterceptor {
isRefreshingToken: boolean = false;
tokenSubject: BehaviorSubject<string> = new BehaviorSubject<string>(null);
constructor(private injector: Injector) {}
addToken(req: HttpRequest<any>, token: string): HttpRequest<any> {
return req.clone({ setHeaders: { Authorization: 'Bearer ' + token }})
}
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpSentEvent | HttpHeaderResponse | HttpProgressEvent | HttpResponse<any> | HttpUserEvent<any>> {
const authService = this.injector.get(AuthService);
return next.handle(this.addToken(req, authService.getAuthToken())).pipe(
catchError(error => {
if (error instanceof HttpErrorResponse) {
switch ((<HttpErrorResponse>error).status) {
case 400:
return this.handle400Error(error);
case 401:
return this.handle401Error(req, next);
default:
return observableThrowError(error);
}
} else {
return observableThrowError(error);
}
}));
}
handle400Error(error) {
if (error && error.status === 400 && error.error && error.error.error === 'invalid_grant') {
// If we get a 400 and the error message is 'invalid_grant', the token is no longer valid so logout.
return this.logoutUser();
}
return observableThrowError(error);
}
handle401Error(req: HttpRequest<any>, next: HttpHandler) {
if (!this.isRefreshingToken) {
this.isRefreshingToken = true;
// Reset here so that the following requests wait until the token
// comes back from the refreshToken call.
this.tokenSubject.next(null);
const authService = this.injector.get(AuthService);
return authService.refreshToken().pipe(
switchMap((newToken: string) => {
if (newToken) {
this.tokenSubject.next(newToken);
return next.handle(this.addToken(this.getNewRequest(req), newToken));
}
// If we don't get a new token, we are in trouble so logout.
return this.logoutUser();
}),
catchError(error => {
// If there is an exception calling 'refreshToken', bad news so logout.
return this.logoutUser();
}),
finalize(() => {
this.isRefreshingToken = false;
}),);
} else {
return this.tokenSubject.pipe(
filter(token => token != null),
take(1),
switchMap(token => {
return next.handle(this.addToken(this.getNewRequest(req), token));
}),);
}
}
/*
This method is only here so the example works.
Do not include in your code, just use 'req' instead of 'this.getNewRequest(req)'.
*/
getNewRequest(req: HttpRequest<any>): HttpRequest<any> {
if (req.url.indexOf('getData') > 0) {
return new HttpRequest('GET', 'http://private-4002d-testerrorresponses.apiary-mock.com/getData');
}
return new HttpRequest('GET', 'http://private-4002d-testerrorresponses.apiary-mock.com/getLookup');
}
logoutUser() {
// Route to the login page (implementation up to you)
return observableThrowError("");
}
}
1条答案
按热度按时间mrwjdhj31#
Yrajaram112,你能给我分配这个问题吗?我想在这个项目上工作。