Angular RxJS - How to monitor progress of HTTP Get Request (not file)

谁说胖子不能爱 提交于 2020-12-31 05:23:07

问题


How to utilize Angular HTTPClient's progress event to show progress in percentage of Get request which does not necessarily a file request?

Currently HTTPClient's progress event fires after request completion. I am hoping to work with Content-Length at back end and determine percentage of content loaded at front end.

I am loading a large amount of rows for a grid and need to show incremental progress on UI. Is it possible?


回答1:


I know this question is older but, i stumbled upon this while searching for an answer to a similar problem and since there is no accepted answer i post my solution.

I recently implemented a generic way to display a progress bar for every request no matter the type in angular 8.

First i created a HttpInterceptor which would automatically intercept every http call where the reportProgress option is set to 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);
    }
  }
}

You need to register this interceptor in your module of course:

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

Basically we're done here, only thing left is that we need to change the way we call our apis. If you want a specific request to be monitored using this interceptor you need to tell angular to report the progress on the 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);
  }
}

This way of calling the httpClient api deliveres a different object when calling .subscribe so we need to take care of that when calling the 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
    }
  });
}

We could also listen here for the HttpEventType.DownloadProgress event and update the progress values inside this component - but that was not the point of my example.

Hint: if you encounter the problem that event.total is undefined - you must check whether your REST backend REALLY is providing the Content-Length header - if this header is missing, you will not be able to calculate the progress!

anyway, i hope this will help somebody someday 😉




回答2:


What about this:

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

...

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

})



回答3:


You can use this

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

Next, pass this request object to the HttpClient.request() method, which returns an Observable of HttpEvents, the same events processed by interceptors:

// 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))
);

Finally you can use that to help

/** 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}.`;
  }
}


来源:https://stackoverflow.com/questions/48461386/angular-rxjs-how-to-monitor-progress-of-http-get-request-not-file

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!