Перехватчик, делающий два вызова в API

Я работаю над проектом, и все работает хорошо... и когда я запрашиваю что-то для API (как в примере ниже), он отправляет, очевидно, только один запрос:

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

Но я хотел воспользоваться преимуществами перехватчиков в новом HttpClient, поэтому я начал искать примеры и нашел это.

Я определил все как в посте:

progress-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;
  }
}

progress-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. Зачем? Я подозреваю, что это потому, что subscribe внутри intercept() из ProgressInterceptor,

Как решить эту проблему?

1 ответ

Решение

Ваше предположение верно, подписавшись на дескриптор внутри перехватчика, вы снова запускаете наблюдаемую цепочку и, следовательно, снова запускаете вызов API.

В вашем случае соответствующий оператор .do(...) ( см. документы), поскольку вы хотите только наблюдать за тем, что происходит внутри цепочки, но не собираетесь манипулировать чем-либо внутри нее.

Это должно выглядеть примерно так:

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;
                }
            });
}
Другие вопросы по тегам