尝试在刷新令牌后使用角度7中的拦截器重复http请求

2024-01-30

我正在尝试在收到带有角度 7 的错误 401 时自动执行刷新令牌请求。

除此之外,我没有找到太多关于如何使用 Angular 7 进行操作的文档,而且我之前没有 Angular 或 RxJS 的知识,我变得有点疯狂

我认为它几乎完成了,但由于某种原因,第二个 next.handle(newRez) 不发送请求(在 google chrome 网络调试器中仅出现第一个请求)

我收到刷新响应并正确处理 LoginResponse(res)

你可以在这里看到我的拦截器

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

let newReq = req.clone();

return next.handle(req).pipe(
  catchError(error => {
    if (error.status == 401) {
      this._authenticationService.refresh().subscribe(
        res => {
          this._authenticationService.processLoginResponse(res);
          newReq.headers.set("Authorization", "Bearer " + this._authenticationService.authResponse.token)
          return next.handle(newReq)
        },
        error => {
          this._authenticationService.logOut();
        });
    }
    throw error;
  })
);

您必须区分所有请求。例如,您不想拦截您的登录请求,也不想拦截刷新令牌请求。 SwitchMap 是你最好的朋友,因为你需要取消一些调用来等待令牌刷新。

因此,您要做的就是首先检查状态 401(未经授权)的错误响应:

return next.handle(this.addToken(req, this.userService.getAccessToken()))
            .pipe(catchError(err => {
                if (err instanceof HttpErrorResponse) {
                    // token is expired refresh and try again
                    if (err.status === 401) {
                        return this.handleUnauthorized(req, next);
                    }

                    // default error handler
                    return this.handleError(err);

                } else {
                    return observableThrowError(err);
                }
            }));

在处理未经授权的函数中,您必须刷新令牌并同时跳过所有进一步的请求:

  handleUnauthorized (req: HttpRequest<any>, next: HttpHandler): Observable<any> {
        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);
            // get a new token via userService.refreshToken
            return this.userService.refreshToken()
                .pipe(switchMap((newToken: string) => {
                    // did we get a new token retry previous request
                    if (newToken) {
                        this.tokenSubject.next(newToken);
                        return next.handle(this.addToken(req, newToken));
                    }

                    // If we don't get a new token, we are in trouble so logout.
                    this.userService.doLogout();
                    return observableThrowError('');
                })
                    , catchError(error => {
                        // If there is an exception calling 'refreshToken', bad news so logout.
                        this.userService.doLogout();
                        return observableThrowError('');
                    })
                    , finalize(() => {
                        this.isRefreshingToken = false;
                    })
                );
        } else {
            return this.tokenSubject
                .pipe(
                    filter(token => token != null)
                    , take(1)
                    , switchMap(token => {
                        return next.handle(this.addToken(req, token));
                    })
                );
        }
    }

我们在拦截器类上有一个属性,用于检查是否已经有刷新令牌请求正在运行:this.isRefreshingToken = true;因为当您触发多个未经授权的请求时,您不希望有多个刷新请求。

所以里面的一切if (!this.isRefreshingToken)部分是关于刷新您的令牌并再次尝试之前的请求。

处理的所有内容else适用于所有请求,同时,当您的 userService 刷新令牌时,会返回 tokenSubject,并且当令牌准备就绪时this.tokenSubject.next(newToken);每个跳过的请求都将被重试。

这篇文章是拦截器的最初灵感:https://www.intertech.com/angular-4-tutorial-handling-refresh-token-with-new-httpinterceptor/ https://www.intertech.com/angular-4-tutorial-handling-refresh-token-with-new-httpinterceptor/

EDIT:

TokenSubject实际上是一个行为主体:tokenSubject: BehaviorSubject<string> = new BehaviorSubject<string>(null);,这意味着任何新订阅者都将获得流中的当前值,这将是我们上次调用时的旧令牌this.tokenSubject.next(newToken).

Withnext(null)每个新订阅者都不会触发switchMap部分,这就是为什么filter(token => token != null)是必要的。

After this.tokenSubject.next(newToken)使用新令牌再次调用每个订阅者都会触发switchMap与新鲜令牌分开。希望现在更清楚了

编辑2020年9月21日

Fix link

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

尝试在刷新令牌后使用角度7中的拦截器重复http请求 的相关文章

随机推荐