javascript - Angular HttpInterceptor : How to use RxJS for multiple conditions

标签 javascript angular typescript rxjs angular-http-interceptors

这是AuthInterceptor:

@Injectable()
export class AuthInterceptor implements HttpInterceptor {

    constructor(private authService: AuthService) { }

    intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {

        const Token = this.authService.getToken();

        if (!Token) {
            return next.handle(req);
        }
 
        // Refresh Token first
        if (Token.expiresRefreshToken && Number(Token.expiresRefreshToken) < Date.now()) {
            this.authService.refreshTokenRefresh(Token.tokenref)
            .subscribe((response) => {
                localStorage.setItem('tokenref', response.tokenref);
                localStorage.setItem('tokenrefexp', response.tokenrefexp);
            });
        }
        // Then next Access Token
        if (Token.expiresToken && Number(Token.expiresToken) < Date.now()) {
            this.authService.refreshToken(Token.tokenref)
            .subscribe((response) => {
                localStorage.setItem('token', response.token);
                localStorage.setItem('tokenexp', response.tokenexp);
            });
        }
        // Original request with updated custom headers
        return next.handle(req.clone({
            headers: req.headers
            .set('Authorization', 'Bearer ' + localStorage.getItem('token'))
            .set('X-Auth-Provider', localStorage.getItem('provider'))
        }));
    }

}

我需要在发送请求之前评估这些条件,因为某些自定义 header 可能会在方法 refreshTokenrefreshTokenRefresh 之后更改。有没有办法评估 RxJS 运算符中的所有内容?第一个条件 (refreshTokenRefresh),然后是第二个条件 (refreshToken),最后是 req

更新:我收到此错误:RangeError: Maximum call stack size exceeded. 如何解决此问题?

最佳答案

我们想等到一些请求完成(评估顺序无关紧要?)而不是另一个请求。

const queue = this.handleRefreshToke(this.handleRefreshTokenRefresh([])); - 在我们调用 next.handle 之前放置所有应该完成的请求。 使用 forkJoin 等待所有请求(放入队列)完成,然后映射到另一个 Obervable(mergeMap)。

PS 我们还可以将 handleRefreshTokenRefreshhandleRefreshToke 移动到单独的 HttpInterceptor。

已编辑 为了防止拦截器的递归调用,我们应该 skip interceptors用于 refreshTokens 调用。

export const InterceptorSkipHeader = 'X-Skip-Interceptor';

@Injectable()
export class AuthInterceptor implements HttpInterceptor {

    constructor(private authService: AuthService) { }

    handleRefreshTokenRefresh(queue: Observable<void>[]) {
        const Token = this.authService.getToken();
        if (Token.expiresRefreshToken && 
            const req = this.authService.refreshTokenRefresh(Token.tokenref)
              .pipe(tap((response) => {
                localStorage.setItem('tokenref', response.tokenref);
                localStorage.setItem('tokenrefexp', response.tokenrefexp);
            }));
            return [...queue, req];
        }
        return queue;
    }

    handleRefreshToke(queue: Observable<void>[]) {
        const Token = this.authService.getToken();
        if (Token.expiresToken && Number(Token.expiresToken) < Date.now()) {
            const req = this.authService.refreshToken(Token.tokenref)
              .subscribe((response) => {
                localStorage.setItem('token', response.token);
                localStorage.setItem('tokenexp', response.tokenexp);
            });
            return [...queue, req];
        }
        return queue;
    }

    intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
       if (req.headers.has(InterceptorSkipHeader)) {
            const headers = req.headers.delete(InterceptorSkipHeader);
            return next.handle(req.clone({ headers }));
        }

        const Token = this.authService.getToken();

        if (!Token) {
            return next.handle(req);
        }

        const queue = this.handleRefreshToke(this.handleRefreshTokenRefresh([]));

        return forkJoin(queue).pipe(
            mergeMap(()=>{
                return next.handle(req.clone({
                    headers: req.headers
                        .set('Authorization', 'Bearer ' + localStorage.getItem('token'))
                        .set('X-Auth-Provider', localStorage.getItem('provider')),
                }));
            })
        );
    }

}

InterceptorSkipHeader 添加到 refreshTokens 以跳过拦截器。

// AuthService

refreshTokenRefresh(token){
   const headers = new HttpHeaders().set(InterceptorSkipHeader, '');
   return this.httpClient
    .get(someUrl, { headers })
}

refreshToken(token){
   const headers = new HttpHeaders().set(InterceptorSkipHeader, '');
   return this.httpClient
    .get(someUrl, { headers })
}

关于javascript - Angular HttpInterceptor : How to use RxJS for multiple conditions,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52848765/

相关文章:

javascript - Angularjs 在生产中未随 Rails 一起加载

javascript - Loop For - 将值的数组与 JS 混合

javascript - Angular 2 - 'imports' 不存在于类型 'ComponentMetadataType' 中

angular - 使用@Input 和@Output 的自定义事件

css - Angular 中的动态 CSS 样式

typescript - TypeScript 和 ES6 的关系

typescript - 确保 typescript 接口(interface)中存在可选属性

javascript - jQuery if 语句未捕获#ID

javascript - Ruby on Rails 实时事件通知

javascript - ReactJS/Typescript/Redux - 具有数据类型编号和逗号值的 onChange 事件