在Angular http拦截器中刷新令牌后重试请求

时间:2020-07-02 17:38:59

标签: angular http rxjs interceptor

当access_token过期时,我有401拦截器,成功处理了一个请求。拦截器重新加载令牌,并返回next.handle(customReq)。但是当同时有2个或更多请求并且两个请求都已过期时,我遇到了问题,因为第二个请求尝试再次刷新,但是现在刷新令牌无效。所以...。我试图设置一个标志仅执行一次,并使用自定义的observable返回。 问题是该组件现在是否成功(如果成功或失败),并且我无法删除加载程序。

http拦截器:

    return next
        .handle(customReq).pipe(
        tap((ev: HttpEvent < any > ) => {
            if (ev instanceof HttpResponse) {
                this.setApiStatus(ApiStatusCode.ACTIVE);
                this.interceptorIgnore.removeIgnore(request.url);
            }
        }),
        catchError(resp => {
            if (resp instanceof HttpErrorResponse) {
                switch (true) {
                    // Unauthorized
                    case resp.status === 401:
                        return this.attemptToRefreshToken(apiRequest, customReq, next);
                    // More code unnecessary ....
                }
            }

            return throwError(resp);
        })
    );

attemptToRefreshToken方法:

attemptToRefreshToken(apiRequest: ApiRequest, customReq: HttpRequest<any>, next: HttpHandler) {


        const retryRequest = () => {
            this.updatingToken = false;
            customReq = customReq.clone({
                headers: apiRequest.buildHeader()
            });
            return next.handle(customReq);
        };

        if (!this.updatingToken) {
            this.updatingToken = true;
            const tokenRequestData = this.apiAuth.refreshTokenData();
            return this.http.request(tokenRequestData.opts.method, tokenRequestData.url, tokenRequestData.opts)
            .pipe(flatMap((token: ResponseTokenFormat) => {
                ApiAuth.storedToken = token;
                this.usersService.queryUsersUsename(ApiAuth.storedUser).then(([user]) => {
                    if (user && !user.isAdmin) {
                        this.sessionService.setUserPermissions(user);
                    }
                });
                this.tokenUpdated.next();
                return retryRequest();
            }));
        }

        return this.tokenUpdated$.pipe(
            flatMap(() => retryRequest())
        );       

}

retryRequest在调用next()时执行,并且运行良好,但从不通知服务对象调用此http请求。返回retryRequest();当我刷新令牌时,令牌可以正常工作,并且该服务可以订阅。

我做错了什么?也许是可观察的?

1 个答案:

答案 0 :(得分:0)

我认为您可能必须在 attemptToRefreshToken 中使用 exhaustMap 代替 flatMap em>。

它们如何工作?

  • flatMap :立即为任何源项目创建一个Observable,所有先前的Observable均保持活动状态
  • exhaustMap :在前一个Observable未完成时,将忽略源项目。