javascript - 在不使用 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 关键字。有没有办法做到这一点?
解决方案
你可以从 Promise 创建一个 observable,并使用mergeMap
operator 来合并你想要返回的 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);
}
推荐阅读
- python - np.array 创建形状与原始形状不同
- html - 与徽标位于同一行的菜单 (html/css)
- ruby - 使用 Ruby 移动十进制固定数量的空格
- sql - SQLite中的双向索引而不复制文本键?
- html - 如何在不扭曲披萨的情况下增加像披萨一样排列的 div 的大小
- java - Java - 调用构造函数时如何使用类属性中的值
- python - 无法在TensorFlow中获取网络的损失函数wrt trainable_variables的tape.gradients
- node.js - 使用 Mongoose,我将如何搜索包含文档内对象的嵌套数组?
- java - FTP 上传适用于虚拟机,但不适用于真机 Android Studio
- android - 获取在 Android 屏幕解锁之前/之后运行哪些应用程序?