Angular RxJS - 如何监控HTTP Get Request(不是文件)的进度

时间:2018-01-26 12:28:23

标签: angular rxjs angular-httpclient

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

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

我正在为网格加载大量行,需要在UI上显示增量进度。有可能吗?

3 个答案:

答案 0 :(得分:5)

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

我最近实现了一种通用方法,无论角度8中的类型如何,都为每个请求显示进度条。

首先,我创建了一个HttpInterceptor,它将自动拦截reportProgress选项设置为true的每个http调用。

@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);
    }
  }
}

您当然需要在您的module中注册此拦截器:

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

基本上我们已经在这里完成了,剩下的就是我们需要改变调用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);
  }
}

这种调用httpClient的api的方法在调用.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
    }
  });
}

我们还可以在这里监听HttpEventType.DownloadProgress事件并更新此组件中的进度值-但这不是我的示例的重点。

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

无论如何,我希望有一天能对某人有所帮助help

答案 1 :(得分:1)

这个怎么样:

CREATE TABLE foo(
                   dt       DATE NOT NULL,
                   f1       REAL NOT NULL,
                   f2       REAL NOT NULL,
                   f3       REAL NOT NULL,
                   f4       REAL NOT NULL
                );



SELECT AVG((f1+f2+f3+f4)/4) as fld_avg FROM
(   
    SELECT date_part('year', dt) AS year_part, 
       date_part('fortnight',  dt) AS fortnight_part,
       f1, f2, f3, f4
    FROM foo
    WHERE dt >= date_trunc('day', NOW() - '3 month')
) foo
GROUP BY year_part, fortnight_part

...

import { HttpEventType, HttpClient, HttpRequest} from '@angular/common/http';

答案 2 :(得分:1)

您可以使用

const req = new HttpRequest('POST', '/upload/file', file, {
reportProgress: true
});

接下来,将此请求对象传递给 HttpClient.request()方法,该方法返回一个 HttpEvents 的Observable,该事件由拦截器处理:

// The `HttpClient.request` API produces a raw event stream
// which includes start (sent), progress, and response events.
return this.http.request(req).pipe(
map(event => this.getEventMessage(event, file)),
tap(message => this.showProgress(message)),
last(), // return last (completed) message to caller
catchError(this.handleError(file))
);

最后,您可以使用它来提供帮助

/** Return distinct message for sent, upload progress, & response events */
private getEventMessage(event: HttpEvent<any>, file: File) {
switch (event.type) {
case HttpEventType.Sent:
  return `Uploading file "${file.name}" of size ${file.size}.`;

case HttpEventType.UploadProgress:
  // Compute and show the % done:
  const percentDone = Math.round(100 * event.loaded / event.total);
  return `File "${file.name}" is ${percentDone}% uploaded.`;

case HttpEventType.Response:
  return `File "${file.name}" was completely uploaded!`;

default:
  return `File "${file.name}" surprising upload event: ${event.type}.`;
  }
}