首页 > 解决方案 > 在Angular http拦截器中刷新令牌后重试请求

问题描述

我有 401 拦截器,当 access_token 过期时,一个请求成功。拦截器重新加载令牌并返回 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);
        })
    );

tryToRefreshToken 方法:

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(); 当我刷新令牌时,它可以正常工作并且服务可以订阅。

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

标签: angularhttprxjsinterceptor

解决方案


我认为您可能必须在 attemptToRefreshToken 中使用exhaustMap不是flatMap

它们是如何工作的?

  • flatMap:立即为任何源项目创建一个 Observable,所有以前的 Observable 都保持活动状态
  • excludeMap:源项被忽略,而前一个 Observable 未完成。

推荐阅读