angular - Angular 7:拦截器中的等待函数
问题描述
我在我的第一个 Angular 应用程序中构建了一个错误拦截器,这对我来说是全新的。401
发生响应代码时,拦截器会尝试刷新 Firebase 授权令牌。因此,我编写了以下代码:
@Injectable()
export class ErrorInterceptor implements HttpInterceptor {
constructor(private authService: AuthService, private alertService: AlertService) { }
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
return next.handle(request).pipe(
catchError(err => {
if (err.status === 401) {
let user = localStorage.getItem('currentUser');
if (!user) {
this.logout(false);
return throwError(err.error);
}
let currentUser = JSON.parse(user);
if (!currentUser || !currentUser.stsTokenManager || !currentUser.stsTokenManager.accessToken) {
this.logout(false);
return throwError(err.error);
}
const reference = this;
this.authService.getToken(currentUser, true).then(t => {
// How do I await and return this properly?
return reference.updateTokenAndRetry(request, next, currentUser, t);
}); // Get token and refresh
}
this.alertService.showAlert({
text: 'Fout tijdens het verzenden van het verzoek',
});
return throwError(err.error);
})
);
}
updateTokenAndRetry(request: HttpRequest<any>, next: HttpHandler, currentUser: any, token: string): Observable<HttpEvent<any>> {
// Update local stored user
currentUser.stsTokenManager.accessToken = token;
localStorage.setItem('currentUser', JSON.stringify(currentUser));
// Add the new token to the request
request = request.clone({
setHeaders: {
Authorization: token,
},
});
return next.handle(request);
}
令牌刷新得很好。然而,网络调用在刷新后没有被执行,这reference.updateTokenAndRetry(request, next, currentUser, t);
应该可以。
我认为这样做的原因是this.authService.getToken(currentUser, true)
返回 a Promise
(这是 Firebase 插件,无法更改)。我想返回return reference.updateTokenAndRetry(request, next, currentUser, t);
,但这是不可能的,因为它位于异步功能块中。
如何等待或返回下一个网络调用?我无法实现该intercept
功能async
。在这一点上,我很困惑。
解决方案
与其尝试返回异步承诺,不如使用 RxJS 'from' 运算符将你的承诺转换为可观察的,如本文所述:将承诺转换为可观察的。
这将为您的拦截器生成正确的 Observable> 返回类型。
您的代码如下所示(假设您一次只发送一个请求):
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
return next.handle(request).pipe(
catchError(err => {
if (err.status === 401) {
let user = localStorage.getItem('currentUser');
if (!user) {
this.logout(false);
return throwError(err.error);
}
let currentUser = JSON.parse(user);
if (!currentUser || !currentUser.stsTokenManager || !currentUser.stsTokenManager.accessToken) {
this.logout(false);
return throwError(err.error);
}
// Return a newly created function here
return this.refreshToken(currentUser, request, next);
}
this.alertService.showAlert({
text: 'Fout tijdens het verzenden van het verzoek',
});
return throwError(err.error);
})
);
}
refreshToken(currentUser: any, request: any, next: any) {
// By making use of the from operator of RxJS convert the promise to an observable
return from(this.authService.getToken(currentUser, true)).pipe(
switchMap(t => this.updateTokenAndRetry(request, next, currentUser, t))
)
}
updateTokenAndRetry(request: HttpRequest<any>, next: HttpHandler, currentUser: any, token: string): Observable<HttpEvent<any>> {
// Update local stored user
currentUser.stsTokenManager.accessToken = token;
localStorage.setItem('currentUser', JSON.stringify(currentUser));
// Add the new token to the request
request = request.clone({
setHeaders: {
Authorization: token,
},
});
return next.handle(request);
}
希望这可以帮助!
推荐阅读
- c# - 在 ASP.NET Core 3 MVC Web 应用程序中设置路由
- docker - 是否可以将 docker 映像与包含源文件的文件夹分开?
- graphql - ApolloGraphQL 中的 useQuery 在第一次调用时会更新缓存,但是 fetchMore 呢?
- unity3d - 在 Unity 中从 nuget 导入 HDF5DotNet 包
- android - 具有自定义 Swipe 视图的 Android Recycler
- gitlab - Argocd 与 GITLAB 存储库的连接
- asp.net - 模态中的动态复选框
- reactjs - 使用 BottomTabNavigator 防止在状态更改后重新渲染
- c# - C# - 将对象序列化为常量变量或直接在 NUnit 的测试用例中使用
- arrays - 如何将 numpy 数组转换为 Zarr 数组