首页 > 解决方案 > 在不使用 async await 关键字的情况下等待 promise 的值?

问题描述

在我的 Angular HttpInterceptor 类中,我实现了一种刷新机制,用于检测 JWT 令牌何时过期,并从后端检索一个新令牌。一旦检索到新的令牌,它将覆盖本地存储中的令牌,从而延长用户会话的到期时间。

HttpInterceptor 的部分功能是在检测到 JWT 到期日期已到时将用户从会话中注销。

但是我遇到了一个问题。发出 JWT 请求后,似乎马上又向后端发送了另一个请求。由于此时令牌已过期,API 将返回 403,并且拦截器正在检测到这一点,并在返回带有新 JWT 令牌的响应之前将用户踢出会话。这意味着用户在令牌有机会刷新之前被注销。

通常这不是问题,因为我可以使用 async/await 来确保在发出任何其他请求之前返回新的 JWT。但是,这在拦截器中不起作用,因为它实现了HttpInterceptor接口,这意味着如果我尝试在接口实现async的方法上使用关键字intercept,那么我会收到编译器错误,因为intercept方法的返回类型必须是Observable<HttpEvent<T>>并且不能是Promise<Observable<HttpEvent<T>>>.

//The below violates the HttpInterceptor interface
async intercept(
    req: HttpRequest<any>,
    next: HttpHandler
  ): Promise<Observable<HttpEvent<any>>> { ... }

//The below violates the async keyword
async intercept(
    req: HttpRequest<any>,
    next: HttpHandler
  ): Observable<HttpEvent<any>> { ... }

我当前的拦截方法代码如下。

intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    req = this.addHeaders(req);

    if(req.headers.has("refreshTokenRequest")) {
      return next.handle(req).pipe(tap(val => console.log("Interceptor handler, req to: " + req.url)));
    }

    if(localStorage.getItem("jwt_token")) {
      if(util.isJwtExpired("jwt_token")) {
        console.log("Jwt is expired, getting new token");
        this.getNewToken().then(newTokenResponse => {  //the .then() method needs to be awaited so that the expired JWT token can be overwritten before ANY other requests are sent
          this._authService.setAuthorizationToken(newTokenResponse.token);
          console.log("New token set");
          return this.handleRequestWithCatchError(req, next);
        });

      }
    }

    return this.handleRequestWithCatchError(req, next);
  }

因此,因此我需要一种方法来等待this.getNewToken()promise 的返回值,而无需使用 async/await 关键字。有没有办法做到这一点?

标签: javascriptangularpromiseasync-await

解决方案


你可以从 Promise 创建一个 observable,并使用mergeMapoperator 来合并你想要返回的 observable。


  import { from } from 'rxjs';
  import { tap, mergeMap } from 'rxjs/operators';

  ...

  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    req = this.addHeaders(req);

    if(req.headers.has("refreshTokenRequest")) {
      return next.handle(req).pipe(tap(val => console.log("Interceptor handler, req to: " + req.url)));
    }

    if(localStorage.getItem("jwt_token")) {
      if(util.isJwtExpired("jwt_token")) {
        console.log("Jwt is expired, getting new token");
        return from(this.getNewToken.call(this)).pipe(
          tap(newTokenResponse => {
            this._authService.setAuthorizationToken(newTokenResponse.token)
          }),
          mergeMap(() => this.handleRequestWithCatchError(req, next))
        )

      }
    }
    return this.handleRequestWithCatchError(req, next);
  }

推荐阅读