gpt4 book ai didi

javascript - token 刷新后, Angular http拦截器不再调用请求

转载 作者:行者123 更新时间:2023-12-03 16:09:31 27 4
gpt4 key购买 nike

我的项目中有一个 http 拦截器,它处理访问 token 的刷新。
当用户的访问 token 过期时,请求将收到 401 错误,在这种情况下,此函数应该处理所有事情,刷新 token 并使用新的访问 token 再次调用请求。
下面是函数的调用:

return next.handle(request).pipe(catchError((error) => {
if (error instanceof HttpErrorResponse && error.status === 401) {
return this.handle401Error(request, next);
} else {
return throwError(error);
}
}));
还有句柄401:
  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));
}));
}
}
我从一篇文章中创建了拦截器,它应该可以正常工作, token 刷新就像一个魅力,但是
return next.handle(this.addToken(request, token.access_token));
哪个应该使用现在有效的 token 再次调用请求只是不调用它。

最佳答案

问题this.auth.refreshAccessToken()返回 promise (我假设给定 .then() )。
解释
以防万一您不熟悉 Promise,它们是处理异步代码的通用系统。这是 link to the docs .this.auth.refreshAccessToken().then()将函数作为参数,通常,您提供了一个匿名箭头函数 (token: Token) => { ... } .
当你这样做 return next.handle(this.addToken(request, token.access_token)); ,您在箭头函数内部,因此您实际上并没有从 handle401Error() 返回值,您将返回一个值到 .then() ..then()确实返回一个值,但您目前没有返回该值。
您可以在 else block 中看到此操作正确完成:

return this.refreshTokenSubject.pipe(                          <-- top-level return
filter((token) => token !== null),
take(1),
switchMap((token) => {
return next.handle(this.addToken(request, token)); <-- nested return
}));
}
解决方案
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));
}));
解释
一件可能让事情变得更容易的小事,我会推荐而不是 any作为 handle401Error() 的返回类型您使用 handle.next() 的返回类型这是 Observable<HttpEvent<any>> .
您需要做的是返回 next.handle() 的值从内部 this.auth.refreshAccessToken().then() .
可能有多种方法可以做到这一点,但我将推荐 Angular/RxJS 风格。
正如我之前所说,promise 就像 observables 一样,RxJS (v6+) 提供了一种将 promise 转换为 observable 的方法,例如:
import { from } from 'rxjs';
const observable = from(promise);
您可以使用它来转换 this.auth.refreshAccessToken()到一个可观察的:
from(this.auth.refreshAccessToken())
现在我们有了一个 observable,你可能倾向于使用 subscribe 来获取值。但这不是您想要做的,因为您的拦截器正在返回一个在其他地方订阅的最终 observable。
你可以做的是使用 pipe ,它允许您使用 RxJS 提供的许多运算符。在这种情况下,您希望等待您的第一个观察到的 refreshAccessToken()发出然后你想返回 next.handle() .此任务常用的运算符是 switchMap .
您会注意到您的 else block 实际上正在使用它:
return this.refreshTokenSubject.pipe(
filter((token) => token !== null),
take(1),
switchMap((token) => { <-- switchMap
return next.handle(this.addToken(request, token));
}));
}
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));
}));
这应该可以解决您的问题,如果这不起作用,请在下面评论。

关于javascript - token 刷新后, Angular http拦截器不再调用请求,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66909610/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com