繁体   English   中英

在不使用异步等待关键字的情况下等待 promise 的值?

[英]Awaiting the value of a promise without using the async await keywords?

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

HttpInterceptor 的 function 的一部分是如果检测到 JWT 到期日期已到,则将用户从其 session 中注销。

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

通常这不是问题,因为我可以使用 async/await 来确保在发出任何其他请求之前返回新的 JWT。 但是,这在拦截器中不起作用,因为它实现了HttpInterceptor接口,这意味着如果我尝试在接口实现的intercept方法上使用async关键字,那么我会得到一个编译器错误,因为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 this.getNewToken() promise 的返回值,而不使用 async/await 关键字。 有没有办法做到这一点?

您可以从 promise 创建一个 observable,并使用mergeMap运算符合并您要返回的 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);
  }

你不应该使用 Promise,而应该使用 observables。

无论如何,只需将它包裹在一个 promise 上,您在加载数据时解决该问题。

req = this.addHeaders(req);
const prom = new Promise((resolve, reject) => {
  if(req.headers.has("refreshTokenRequest")) {
  // Your code here
  }
})

return prom.then(v => this.handleRequestWithCatchError(req, next));

编辑

正如@mbojko指出的那样,返回一个可观察对象(就像我首先说的那样),因为签名不接受承诺。

return from(prom.then(v => this.handleRequestWithCatchError(req, next)));

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM