javascript - 刷新 token 拦截器 ionic 时捕获错误

标签 javascript angular rxjs ionic3 interceptor

我正在使用 ionic 3、Angular 5 和 rxjs 5。 我在我的应用程序中创建了拦截器,并且可以很好地拦截所有传出 API,并向 header 添加 token ,并在原始 token 过期时刷新 token 。

import {Observable, BehaviorSubject} from 'rxjs';
import {_throw} from "rxjs/observable/throw";

import {take, filter, catchError, switchMap, finalize} from 'rxjs/operators';
import {Injectable, Injector} from "@angular/core";
import {HttpInterceptor, HttpRequest, HttpHandler, HttpSentEvent, HttpHeaderResponse, HttpProgressEvent,
  HttpResponse, HttpUserEvent, HttpErrorResponse} from "@angular/common/http";

import {ResetApiProvider} from "../providers/reset-api/reset-api";
import {Events} from "ionic-angular";

@Injectable()
export class AuthInterceptor implements HttpInterceptor {

  isRefreshingToken: boolean = false;
  tokenSubject: BehaviorSubject<string> = new BehaviorSubject<string>(null);

  constructor(private injector: Injector, public event: Events) {}

  addToken(req: HttpRequest<any>, token: string): HttpRequest<any> {
    return req.clone({setHeaders: {Authorization: 'Bearer ' + token}})
  }

  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpSentEvent | HttpHeaderResponse | HttpProgressEvent | HttpResponse<any> | HttpUserEvent<any>> {
    const authService = this.injector.get(ResetApiProvider);

    return next.handle(this.addToken(req, authService.getAuthToken())).pipe(
      catchError(error => {
        if (error instanceof HttpErrorResponse) {
          switch ((<HttpErrorResponse>error).status) {
            case 400:
              return this.handle400Error(error);
            case 401:
              return this.handle401Error(req, next);
            default:
              return _throw(error);
          }
        } else {
          return _throw(error);
        }
      }));
  }

  //maybe use later for blacklist tokens
  handle400Error(error) {
    if (error && error.status === 400 && error.error && error.error.error === 'invalid_grant') {
      // If we get a 400 and the error message is 'invalid_grant', the token is no longer valid so logout.
      return this.logoutUser();
    }

    return _throw(error);
  }

  handle401Error(req: HttpRequest<any>, next: HttpHandler) {
    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);

      const authService = this.injector.get(ResetApiProvider);

      return authService.refreshToken().pipe(
        switchMap((newToken: string) => {
          console.log('bbbbbbb');
          if (newToken) {
            this.tokenSubject.next(newToken);
            return next.handle(this.addToken(req, newToken));
          }
          console.log('qqqq');

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

  logoutUser() {
    const authService = this.injector.get(ResetApiProvider);
    authService.logout();
    this.event.publish('UNAUTHORIZED');
    return _throw("please login");
  }


}

我的刷新 token 功能:

public refreshToken(): Observable<string> {
    const url = `${apiUrl}/auth/refresh`;
    console.log('fffff');
    return this.http.post(url, {token: this.getAuthToken()},httpOptions)
      .pipe(
        map((res) => {
          let token: any = res;
          this.storage.set('token', token.data);
          console.log(token.data);
          this.currentToken = token.data;
           return  token.data;
        catchError(this.handleError)
      );
  }

除非,如果refreshToken()失败,则在AuthInterceptor类中永远不会到达catch()和finally()!如何解决这个问题!? 所以我无法清除存储并导航到登录页面。

最佳答案

尝试这个调整。

public refreshToken(): Observable<string> {
    const url = `${apiUrl}/auth/refresh`;
    console.log('fffff');
    return this.http.post(url, {token: this.getAuthToken()},httpOptions)
      .pipe(
        map((res) => {
          let token: any = res;
          this.storage.set('token', token.data);
          console.log(token.data);
          this.currentToken = token.data;
          //return  token.data;
        }),
        catchError(this.handleError)
      );
}
  • 即return 和 catchError 之间缺少的 }),
  • return 似乎也是多余的,所以我注释掉了。

here .

请告诉我这是否有帮助。

关于javascript - 刷新 token 拦截器 ionic 时捕获错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54929047/

相关文章:

java - 使用 js/jquery/java/active x 或其他方式拍摄 <div> 的快照?

javascript - 如何获取JSX输入字段的值到Javascript日期对象,然后将其插入mysql YYYY-MM-DD格式?

angular - Typescript + pouchdb远程登录不是一个函数

javascript - Angular HttpInterceptor 不适用于 forkJoin

typescript - Angular2 Http with RXJS Observable TypeError : this. http.get(...).map(...).catch 不是函数

javascript - Angular - 将 HTTP 发布数据发送到服务器 [HOW TO]

javascript - jquerymobile 动态添加选择菜单

angular - Angular 是否需要reflectmetadata.js和emitDecoratorMetadata : true?

javascript - 在 Google App Engine 上重命名 index.html

node.js - 以 react 方式查询 mongodb 集合中所有文档的最佳方法,无需溢出 RAM