Angular RxJS - 如何监控 HTTP Get 请求(非文件)的进度

abd*_*hab 5 rxjs angular angular-httpclient

如何利用 Angular HTTPClient 的progress事件来显示不一定是文件请求的 Get 请求的百分比进度?

当前 HTTPClient 的progress事件在请求完成后触发。我希望Content-Length在后端工作并确定前端加载的内容百分比。

我正在为网格加载大量行,并且需要在 UI 上显示增量进度。是否可以?

Seb*_*ian 8

我知道这个问题比较老,但是,我在寻找类似问题的答案时偶然发现了这个问题,由于没有公认的答案,我发布了我的解决方案。

我最近实现了一种通用方式来为每个请求显示一个进度条,而不管 angular 8 中的类型是什么。

首先,我创建了一个HttpInterceptor它会自动拦截每个 http 调用,其中该reportProgress选项设置为true.

@Injectable()
export class HttpProgressInterceptor implements HttpInterceptor {

  constructor(
    private spinnerService: SpinnerService // my personal service for the progress bar - replace with your own
  ) {}

  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    if (req.reportProgress) {
      // only intercept when the request is configured to report its progress
      return next.handle(req).pipe(
        tap((event: HttpEvent<any>) => {
          if (event.type === HttpEventType.DownloadProgress) {
            // here we get the updated progress values, call your service or what ever here
            this.spinnerService.updateGlobalProgress(Math.round(event.loaded / event.total * 100)); // display & update progress bar
          } else if (event.type === HttpEventType.Response) {
            this.spinnerService.updateGlobalProgress(null); // hide progress bar
          }
        }, error => {
          this.spinnerService.updateGlobalProgress(null); // hide progress bar
        })
      );
    } else {
      return next.handle(req);
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

您需要在您module的课程中注册此拦截器:

@NgModule({
  declarations: [
    AppComponent,
    ...
  ],
  imports: [
    BrowserModule,
    ...
    RouterModule.forRoot(appRoutes)
  ],
  providers: [
    ...
    { provide: HTTP_INTERCEPTORS, useClass: HttpProgressInterceptor, multi: true },
    ...}
  ],
  bootstrap: [AppComponent]
})
export class AppModule { }
Run Code Online (Sandbox Code Playgroud)

基本上我们到这里就完成了,剩下的就是我们需要改变我们调用 api 的方式。如果您希望使用此拦截器监视特定请求,则需要告诉 angular 报告 HttpRequest 的进度:

@Injectable()
export class MyService {

  constructor(
    private http: HttpClient
  ) {}

  myGetMethod() {
    const url = "api/data/load/big/data";
    const req = new HttpRequest("GET", url, {
      reportProgress: true  // this is important!
    });

    return this.http.request(req);
  }
}
Run Code Online (Sandbox Code Playgroud)

这种调用httpClientapi 的方式在调用时会传递一个不同的对象,.subscribe因此我们在调用时需要注意myGetMethod()

ngOnInit() {
  this.myService.myGetMethod().subscribe((event: HttpEvent<any>) => {
    if (event.type === HttpEventType.Response) {
      const responseData = event.body;
      console.dir(responseData); // do something with the response
    }
  });
}
Run Code Online (Sandbox Code Playgroud)

我们也可以在这里监听HttpEventType.DownloadProgress事件并更新这个组件内的进度值——但这不是我的例子的重点。

提示:如果您遇到event.total未定义的问题- 您必须检查您的 REST 后端是否真的提供了Content-Length标题 - 如果缺少此标题,您将无法计算进度!

无论如何,我希望这有一天会帮助某人


Mar*_*ers 4

那这个呢:

import { HttpEventType, HttpClient, HttpRequest} from '@angular/common/http';
Run Code Online (Sandbox Code Playgroud)

...

const request = new HttpRequest('GET', url,  {
  reportProgress: true
});

http.request(request).subscribe(event => {

  // progress
  if (event.type === HttpEventType.DownloadProgress) {
    console.log(event.loaded, event.total); 
    // event.loaded = bytes transfered 
    // event.total = "Content-Length", set by the server

    const percentage = 100 / event.total * event.loaded;
    console.log(percentage);
  }

  // finished
  if (event.type === HttpEventType.Response) {
    console.log(event.body);
  }

})
Run Code Online (Sandbox Code Playgroud)