拦截器在 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;
}
});
}
我正在做一个项目并且一切正常...当我向 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;
}
});
}