拦截器在 API 中进行两次调用

Interceptor making two calls in API

我正在做一个项目并且一切正常...当我向 API 请求某些东西时(如下例所示)它显然只发送一个请求:

this.httpClient.get<MyInterface>('my_api').subscribe(data => this.items = data);

但是我想在新的 HttpClient 中利用拦截器,所以我开始搜索示例并找到 this

我已经定义了 post 中的所有内容:

进度-interceptor.ts:

@Injectable()
export class ProgressInterceptor implements HttpInterceptor {

  progress$: Observable<number | null>;
  private progressSubject: Subject<number | null>;

  constructor() {
    this.progressSubject = new ReplaySubject<number | null>(1);
    this.progress$ = this.progressSubject.asObservable();
  }

  intercept<T>(req: HttpRequest<T>, next: HttpHandler): Observable<HttpEvent<T>> {
    const reportingRequest = req.clone({ reportProgress: true });
    const handle = next.handle(reportingRequest);

    handle.subscribe((event: HttpEvent<T>) => {
      switch (event.type) {
        case HttpEventType.Sent:
          this.progressSubject.next(undefined);
          break;

        case HttpEventType.DownloadProgress:
        case HttpEventType.UploadProgress:
          if (event.total) {
            this.progressSubject.next(Math.round((event.loaded / event.total) * 100));
          }
          break;

        case HttpEventType.Response:
          this.progressSubject.next(100);
          break;

        default:
        break;
      }
    });

    return handle;
  }
}

进度-component.ts:

export class ProgressComponent implements OnInit {

  progressPercentage$: Observable<number>;

  @Input() color: ProgressBarColor = 'primary';

  @ViewChild(MdProgressBar) private progressBar: MdProgressBar;

  constructor(private interceptor: ProgressInterceptor) { }

  ngOnInit(): void {
    this.progressPercentage$ = this.interceptor.progress$
        .map(progress => {
          if (isNil(progress)) {
            this.setMode('indeterminate');

            return 0;
          } else {
            this.setMode('determinate');

            return progress;
          }
        });
  }

  private setMode(mode: ProgressBarMode) {
    this.progressBar.mode = mode;
  }
}

app.module.ts:

const interceptor = new ProgressInterceptor();

@NgModule({
  // ...
  providers: [
    { provide: ProgressInterceptor, useValue: interceptor },
    { provide: HTTP_INTERCEPTORS, useValue: interceptor, multi: true }
  ]
})

问题是:现在,有了这个拦截器,当我发出任何请求时,它会命中 API 两次。为什么?我怀疑那是因为 ProgressInterceptor.

intercept() 里面的 subscribe

如何解决这个问题?

您的猜测是正确的,通过订阅拦截器中的句柄,您将再次触发可观察链,因此再次触发 API 调用。

在您的情况下,合适的运算符是 .do(...) (see the docs),因为您只想观察链内发生的事情,但无意操纵其中的任何内容。

它应该看起来像这样:

intercept<T>(req: HttpRequest<T>, next: HttpHandler): Observable<HttpEvent<T>> {
  const reportingRequest = req.clone({ reportProgress: true });
  return next.handle(reportingRequest)
             .do((event: HttpEvent<T>) => {
                switch (event.type) {
                  case HttpEventType.Sent:
                    this.progressSubject.next(undefined);
                    break;

                  case HttpEventType.DownloadProgress:
                  case HttpEventType.UploadProgress:
                    if (event.total) {
                      this.progressSubject.next(Math.round((event.loaded / event.total) * 100));
                    }
                    break;

                  case HttpEventType.Response:
                    this.progressSubject.next(100);
                    break;

                  default:
                  break;
                }
            });
}