Angular HTTP拦截器-无法从内部订阅返回 [英] Angular HTTP interceptor - Cannot return from inner subscription

查看:60
本文介绍了Angular HTTP拦截器-无法从内部订阅返回的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试实现HTTP拦截器,因此当令牌过期时,我会得到refresh_token,然后调用 return next.handle(request); ,但看来我无法返回从主管.如果我尝试以/API_URL/page1的身份访问我的页面,并且返回401状态,那么我将获得刷新令牌,但应该再次调用/API_URL/page1,而不会.我使用"rxjs":"6.5.5" .这是我的代码:

I am trying to implement an HTTP interceptor so when the token is expired, I get the refresh_token, and then I call return next.handle(request);, but it seems like I cannot return from the main pipe. If I try to access my page as /API_URL/page1 and this returns a 401 status, I then get the refresh token, but /API_URL/page1 should be called again and it is not. I use "rxjs": "6.5.5". This is my code:

intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    const currentUser = this.lsService.getItem('currentUser') as any;

    if(currentUser && currentUser.accessToken && this.checkIfUrlNeedsToken(request)) {
      request = request.clone({ headers: request.headers.set('Authorization', currentUser.accessToken) });
    }

    return next.handle(request)
      .pipe(tap(
        (event: HttpEvent<any>) => {
          if (event instanceof HttpResponse) {
            // do stuff with response if you want
          }
        }, (err: any) => {
          if(this.isRefreshTokenExpiredError(err)) {
            this.redirectToLogin();
          } else if(this.isAuthError(err) && this.checkIfUrlNeedsToken(request)) {
            return this.authService.getNewToken().subscribe((response: User): Observable<HttpEvent<any>> => {
              this.lsService.setItem('currentUser', response);  //  Rewrite the current user
              request = request.clone({ headers: request.headers.set('Authorization', response.accessToken) });
              return next.handle(request);
            }); 
          } else {
            this.redirectToLogin();
          }
        }
      ));
  }

请告知.谢谢!

推荐答案

您不能从订阅中返回值-您必须使用 switchMap concatMap .

You can't return a value from a subscribe - you have to return the observable from within the pipe using either a switchMap or a concatMap.

此外, tap 正在产生副作用.您不能从 tap 返回.在您的情况下,您需要从 catchError 返回.

Also, tap is performing side-effects. You cannot return from a tap. In your case you will need to return from a catchError.

intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
  const currentUser = this.lsService.getItem('currentUser') as any;

  if(currentUser && currentUser.accessToken && this.checkIfUrlNeedsToken(request)) {
    request = request.clone({ headers: request.headers.set('Authorization', currentUser.accessToken) });
  }

  return next.handle(request)
    .pipe(
      tap((event: HttpEvent<any>) => {
        if (event instanceof HttpResponse) {
          // do stuff with response if you want
        }
      }, (err: any) => {
        if (this.isRefreshTokenExpiredError(err)) {
          this.redirectToLogin();
        } else if(this.isAuthError(err) && this.checkIfUrlNeedsToken(request)) {
          // handle in catchError
        } else {
          this.redirectToLogin();
        }
      }),
      catchError((err: any) => {
        if(!this.isAuthError(err) || !this.checkIfUrlNeedsToken(request)) {
          return throwError(err);
        }

        return this.authService.getNewToken().pipe(
          switchMap((response: User): Observable<HttpEvent<any>> => {
            //  Rewrite the current user
            this.lsService.setItem('currentUser', response); 
            request = request.clone({ headers: request.headers.set('Authorization', response.accessToken) });
            return next.handle(request);
          }); 
      })
    );
  }

通过管道的错误操作流程现在类似于:

The flow of error actions through the pipe is now something like:

  • 点击:如有必要,重定向
  • catchError:如有必要,获取新令牌
    • switchMap:重新运行http请求

    我已将可观察对象移动到 catchError 内的 switchMap 中.我没有在 tap 中更改您的任何逻辑-现在可以简化了.

    I have moved the observable into a switchMap inside a catchError. I haven't changed any of your logic inside the tap - that can probably be simplified now.

    这篇关于Angular HTTP拦截器-无法从内部订阅返回的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆