Перехватчик, делающий два вызова в 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;
}
});
}