首页 > 解决方案 > 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。在这一点上,我很困惑。

标签: angulartypescriptangular7

解决方案


与其尝试返回异步承诺,不如使用 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);
}

希望这可以帮助!


推荐阅读