簡體   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