Angular 6 HTTP拦截器-捕获错误并重新发送请求后,视图未更新

时间:2018-10-06 07:57:12

标签: angular angular-http-interceptors

我正在如下特定路径上测试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;
}

1 个答案:

答案 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功能,但是它对我来说可以确保从拦截器返回时刷新视图。