简体   繁体   English

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

[英]Angular 6 HTTP Interceptor - view not updated after catching error and rebmitting request

I am testing my HTTP Angular 6 Interceptor google token refresh functionality on a specific route as below. 我正在以下特定路径上测试HTTP Angular 6 Interceptor谷歌令牌刷新功能。

It works (The request is re-sent with a new token and the data is returned) but the view that made the request is not updated (it is when not using the Interceptor). 它可以工作(使用新令牌重新发送请求并返回数据),但是发出请求的视图未更新(即不使用Interceptor时)。

Adding detectChanges() in the calling component in the http call's .then() will fix it but I don't want to have to add this (or NgZone.run()) to every http req in my app.. 在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;
}

I was finally able to find a solution based on this answer: Http requests made from Ngxs state doesn't get detected by Angular (zone related issue) 我终于能够找到基于此答案的解决方案: Angular不会检测到从Ngxs状态发出的Http请求(与区域相关的问题)

Wrap the next.handle in an ngZone run(): 将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()); }
      });
    });
  };
}

I am not sure why the enterZone functionality is required on top of the standard zone.run() method but it worked for me in ensuring the view was refreshed when returning form the interceptor. 我不确定为什么在标准zone.run()方法之上需要enterZone功能,但是它对我有用,可确保从拦截器返回时刷新视图。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM