我正在如下特定路径上测试HTTP Angular 6 Interceptor谷歌令牌刷新功能。
它有效(使用新令牌重新发送请求并返回数据),但发出请求的视图未更新(即不使用拦截器时)。
在http调用的.then()的调用组件中添加detectChanges()可以解决该问题,但我不想将此应用(或NgZone.run())添加到应用中的每个http请求中。
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
if (req.url === 'XXX') {
return this.refreshToken().pipe(
switchMap(() => {
req = this.addToken(req);
return next.handle(req);
})
, catchError(() => {
this.authService.signOut();
return throwError('');
})
);
}
...
}
/* Get new google ID token in Auth service and inform when done*/
refreshToken() {
if (this.refreshTokenInProgress) {
return new Observable(observer => {
this.tokenRefreshed$.subscribe(() => {
observer.next();
observer.complete();
});
});
} else {
this.refreshTokenInProgress = true;
return from(this.authService.refreshToken()).pipe(
tap(() => {
this.refreshTokenInProgress = false;
this.tokenRefreshedSource.next();
})
);
}
}
/* Add google id token to request header */
addToken(request) {
const token = this.authService.googleIdToken;
if (token) {
return request.clone({ headers: request.headers.set('google-id-token', token) });
}
return request;
}
答案 0 :(得分:0)
我终于能够根据以下答案找到解决方案: Http requests made from Ngxs state doesn't get detected by Angular (zone related issue)
将next.handle包装在ngZone run()中:
return this._ngZone.run(() => {
return next.handle(req).pipe(enterZone(this._ngZone));
});
function enterZone<T>(zone: NgZone) {
return (source: Observable<T>) => {
return new Observable((sink: Observer<T>) => {
return source.subscribe({
next(x) { zone.run(() => sink.next(x)); },
error(e) { zone.run(() => sink.error(e)); },
complete() { zone.run(() => sink.complete()); }
});
});
};
}
我不确定为什么在标准zone.run()方法之上需要enterZone功能,但是它对我来说可以确保从拦截器返回时刷新视图。