Ionic 在拦截器上刷新令牌时,SwitchMap未触发

kcugc4gi  于 12个月前  发布在  Ionic
关注(0)|答案(1)|浏览(178)

我已经使用Angular在一个离子应用程序的http拦截器中实现了一个刷新令牌过程,我想我错过了一些让代码正常工作的东西:
refreshTokens令牌函数:

async refreshTokens() {
  return new Promise((resolve, reject) => {
    this.dataService
      .post(this.apiUriService.refreshTokenUri(), {
        refresh_token: this.authData.refreshToken,
      })
      .pipe(take(1))
      .subscribe({
        next: (res: any) => {
          if (!res) {
            return reject(null);
          }
          const resData = res.data ? res.data : null;
          this.utils.setItemOnLocalStorage(
            Constants.authDataStorageItemName,
            resData
          );
          resolve(resData);
        },
        error: (error) => {
          return reject(error);
        },
      });
  });
}

字符串
和错误401错误功能:

async handle401Error(req: HttpRequest<any>, next: HttpHandler, error: any) {
  return from(this.refreshTokens()).pipe(
    switchMap((res: any) => {
      console.log('switchMap fired!');
      const request = this.addToken(req, res.access_token);
      return next.handle(request);
    }),
    catchError((error) => {
      this.logoutUser();
      return throwError(error);
    })
  );
}


下面是完整的拦截器类代码:

import { Injectable } from '@angular/core';
import { Router } from '@angular/router';
import {
  HttpRequest,
  HttpResponse,
  HttpHandler,
  HttpEvent,
  HttpInterceptor,
  HttpErrorResponse,
} from '@angular/common/http';
import {
  Observable,
  throwError,
  BehaviorSubject,
  tap,
  take,
  from,
  switchMap,
  catchError,
} from 'rxjs';
import { AuthService } from './auth/auth.service';
import { ApiUriService } from './api-uri.service';
import { DataService } from './data.service';
import { Constants } from '../constants/constants';
import { CommonUtilsService } from './common-utils.service';
import { UserService } from './user/user.service';

@Injectable()
export class CommonHttpInterceptor implements HttpInterceptor {
  tokenSubject: BehaviorSubject<string> = new BehaviorSubject<string>('');

  get authData() {
    return this.authService.readUserInfoFromLocalStorage();
  }

  constructor(
    private authService: AuthService,
    private router: Router,
    private apiUriService: ApiUriService,
    private dataService: DataService,
    private userService: UserService,
    private utils: CommonUtilsService
  ) {}

  intercept(
    request: HttpRequest<unknown>,
    next: HttpHandler
  ): Observable<HttpEvent<unknown>> {
    const userInfoData = this.authService.authUserData;
    const headers: any = {};

    if (userInfoData && userInfoData.accessToken) {
      headers['Authorization'] = `Bearer ${userInfoData.accessToken}`;
    }

    const clonedRequest = request.clone({ setHeaders: headers });

    return next.handle(clonedRequest).pipe(
      tap(
        (event: HttpEvent<any>) => {
          if (event instanceof HttpResponse) {
            // case when we need to transform the response
          }
        },
        (error: HttpErrorResponse) => {
          // handle  refresh token in case of the access token is expired
          if (error.status === 401) {
            return this.handle401Error(request, next);
          }
          return throwError(error);
        }
      )
    );
  }

  logoutUser() {
    this.authService.doLogout();
    this.router.navigate(['auth/login']);
  }

  handle401Error(req: HttpRequest<any>, next: HttpHandler) {
    return from(this.refreshTokens()).pipe(
      switchMap((res: any) => {
        console.log('switchMap fired!');
        const request = this.addToken(req, res.access_token);
        return next.handle(request);
      }),
      catchError((error) => {
        this.logoutUser();
        return throwError(error);
      })
    );
  }

  // refresh access token OR logout user if request failed
  refreshTokens() {
    return new Promise((resolve, reject) => {
      this.dataService
        .post(this.apiUriService.refreshTokenUri(), {
          refresh_token: this.authData.refreshToken,
        })
        .pipe(take(1))
        .subscribe({
          next: (res: any) => {
            if (!res) {
              return reject(null);
            }
            const resData = res.data ? res.data : null;
            this.utils.setItemOnLocalStorage(
              Constants.authDataStorageItemName,
              resData
            );
            resolve(resData);
          },
          error: (error) => {
            return reject(error);
          },
        });
    });
  }

  //add token to authorization header
  private addToken(request: HttpRequest<any>, token: any) {
    const newToken = this.authService.shiftoCookieValue
      ? this.authService.shiftoCookieValue
      : token;
    if (newToken) {
      let clone: HttpRequest<any>;
      clone = request.clone({
        setHeaders: {
          Authorization: `Bearer ${token}`,
        },
      });
      return clone;
    }
    return request;
  }
}


我的问题是switchMap没有被触发,也没有在控制台中记录任何日志。所以没有发送下一个请求。

j5fpnvbx

j5fpnvbx1#

问题是,您的错误处理程序方法在tap()内部被调用,结果Observable被返回。但在tap()中,返回值被忽略,因此Observable不会被订阅。
你可以使用catchError,返回的Observable将被订阅。

return next.handle(clonedRequest).pipe(
  catchError((error: HttpErrorResponse) => {
    if (error.status === 401) {
      return this.handle401Error(request, next);
    }
    return throwError(() => error);
  })
);

字符串

相关问题