Mát*_*tal 5 javascript http interceptor typescript angular
我的项目中有一个 http 拦截器,它处理访问令牌的刷新。
当用户的访问令牌过期时,请求将收到 401 错误,在这种情况下,此函数应处理所有内容,刷新令牌并使用新的访问令牌再次调用请求。
下面是函数的调用:
return next.handle(request).pipe(catchError((error) => {
if (error instanceof HttpErrorResponse && error.status === 401) {
return this.handle401Error(request, next);
} else {
return throwError(error);
}
}));
Run Code Online (Sandbox Code Playgroud)
和 handle401:
handle401Error(request: HttpRequest<any>, next: HttpHandler): any {
if (!this.isRefreshing) {
this.isRefreshing = true;
this.refreshTokenSubject.next(null);
this.auth.refreshAccessToken().then((token: Token) => {
this.isRefreshing = false;
this.refreshTokenSubject.next(token.access_token);
return next.handle(this.addToken(request, token.access_token));
});
} else {
return this.refreshTokenSubject.pipe(
filter((token) => token !== null),
take(1),
switchMap((token) => {
return next.handle(this.addToken(request, token));
}));
}
}
Run Code Online (Sandbox Code Playgroud)
我从一篇文章中创建了拦截器,它应该可以正常工作,令牌刷新就像一个魅力,但是
return next.handle(this.addToken(request, token.access_token));
Run Code Online (Sandbox Code Playgroud)
哪个应该使用现在有效的令牌再次调用请求只是不调用它。
this.auth.refreshAccessToken()
返回一个承诺(我假设给定了.then()
)。
以防万一您不熟悉promise,它们是处理异步代码的常用系统。这是文档的链接。
在this.auth.refreshAccessToken().then()
接受一个函数作为参数,因为是共同的,你提供了一个匿名箭头功能(token: Token) => { ... }
。
当你这样做时return next.handle(this.addToken(request, token.access_token));
,你是在箭头函数中,所以你实际上不是从 返回一个值handle401Error()
,而是返回一个值到.then()
。
.then()
确实返回一个值,但您目前没有返回该值。
您可以在 else 块中看到正确完成此操作:
return this.refreshTokenSubject.pipe( <-- top-level return
filter((token) => token !== null),
take(1),
switchMap((token) => {
return next.handle(this.addToken(request, token)); <-- nested return
}));
}
Run Code Online (Sandbox Code Playgroud)
TLDR;
return from(this.auth.refreshAccessToken()).pipe(switchMap((token: Token) => {
this.isRefreshing = false;
this.refreshTokenSubject.next(token.access_token);
return next.handle(this.addToken(request, token.access_token));
}));
Run Code Online (Sandbox Code Playgroud)
这可能使事情变得更容易一件小事,我会建议,而不是any
作为返回类型handle401Error()
使用返回类型的handle.next()
这是Observable<HttpEvent<any>>
。
您需要做的是next.handle()
从 inside返回值this.auth.refreshAccessToken().then()
。
可能有多种方法可以做到这一点,但我将推荐 Angular/RxJS 风格。
正如我之前所说,promise 就像 observables,而 RxJS (v6+) 提供了一种将 promise 转换为 observable 的方法,例如:
import { from } from 'rxjs';
const observable = from(promise);
Run Code Online (Sandbox Code Playgroud)
您可以使用它来转换this.auth.refreshAccessToken()
为 observable:
from(this.auth.refreshAccessToken())
Run Code Online (Sandbox Code Playgroud)
现在我们有了一个 observable,您可能倾向于使用它来获取值,subscribe
但这不是您想要做的,因为您的拦截器正在返回一个在其他地方订阅的最终 observable。
你可以做的是使用pipe,它允许你使用 RxJS 提供的许多运算符。在这种情况下,您希望等待第一个 observablerefreshAccessToken()
发出,然后返回next.handle()
。此任务常用的运算符是switchMap。
你会注意到你的 else 块实际上是在使用这个:
return this.refreshTokenSubject.pipe(
filter((token) => token !== null),
take(1),
switchMap((token) => { <-- switchMap
return next.handle(this.addToken(request, token));
}));
}
Run Code Online (Sandbox Code Playgroud)
switchMap()
等待第一个 observable 发出,然后将值输出到您的回调函数中,期待您返回另一个 observable。在您的情况下,这意味着您将替换then()
为pipe(switchMap())
.
如 TLDR 所示:
return from(this.auth.refreshAccessToken()).pipe(switchMap((token: Token) => {
this.isRefreshing = false;
this.refreshTokenSubject.next(token.access_token);
return next.handle(this.addToken(request, token.access_token));
}));
Run Code Online (Sandbox Code Playgroud)
这应该可以解决您的问题,如果这不起作用,请在下面发表评论。
归档时间: |
|
查看次数: |
145 次 |
最近记录: |