2

I am using HttpInterceptor and I have an Http service that calls http methods running HttpClient. I am trying to get the progress of the upload and I am facing two issues here,

First, progress event is only being caught by HttpInterceptor and not any of my Http caller methods in my service. it looks like the former is masking the progress reporting.

Second, The progress value always starts with 100%, and the it starts the increment.

I am lazily loading my module, HttpInterceptor is registered at the app.module level.

How can I get the progress value from an http method?

my HttpInterceptor service looks like,

if (req.url.search('https') < 0) {
      const headers = new HttpHeaders({
        Accept: 'application/json',
        Authorization: `Bearer ${this.authService.getToken()}`,
        'X-XSRF-TOKEN': `${this.authService.getAntiforgeryToken()}`,
        ClientTimeZoneOffest: `${new Date().getTimezoneOffset()}`,
        ClientTimeZoneId: Intl.DateTimeFormat().resolvedOptions().timeZone,
        ClinetLogInId: `${this.authService.getLogInId()}`,
      });
      const cloneReq = req.clone({ headers });
      return next.handle(cloneReq).pipe(
        mergeMap((ev: HttpEvent<any>) => {
          if (ev.type === HttpEventType.UploadProgress) {
            const percentDone = Math.round((100 * ev.loaded) / ev.total);
            console.log(`File is ${percentDone}% uploaded.`);
          }
          this.httpResponseHandlerService.handleSuccessResponse(ev);
          return Observable.of(ev);
        }),
        catchError(error => {
          this.httpResponseHandlerService.handleErrorResponse(error, req);
          return Observable.throw(error);
        }),
      );
    } else {
      return next.handle(req);
    }
  }

my Http caller service,

public upload<T>(apiUrl: string, jsonData: {} = {}) {
    return this.httpService.post<T>(this.baseUrl + apiUrl, jsonData, {
      reportProgress: true,
    });
  }

and the method where I am trying to get the progress in is like,

this.httpService
        .upload(this.api + this.id.value, data)
        .takeUntil(this.unsubscribe)
        .subscribe((ev: HttpEvent<any>) => { // Nothing is happening here!
          if (ev.type === HttpEventType.UploadProgress) {
            const percentDone = Math.round((100 * ev.loaded) / ev.total);
            console.log(`File is ${percentDone}% uploaded.`);
          }
        });

The progress behavior is,

enter image description here

Envil
  • 2,687
  • 1
  • 30
  • 42
JSON
  • 1,583
  • 4
  • 31
  • 63
  • You are missing the `obeserve: 'events'` parameter when making the request. And upload progress calculation should be `event.loaded / event.total * 100` – nightElf91 Jul 02 '18 at 08:06
  • did you try adding the `observe` ? @JSON – nightElf91 Jul 02 '18 at 08:38
  • @nightElf91, thank you, yes I tried, what worked for me is changing my caller method from `post` to `request` – JSON Jul 02 '18 at 08:48

1 Answers1

2

The way you're performing the request is incorrect, please refer to http://angular.io/guide/http#listening-to-progress-events

You should create an HttpRequest then call this.http.request(req) instead of this.http.post(...)

http.post is just the short-hand for performing normal http request by http.request. For full request creating options, like when we want to download or upload with progress tracking, you should go with the http.request (where you manually create the request object with many options, then perform it).

Also quoted from the document:

// The HttpClient.request API produces a raw event stream

// which includes start (sent), progress, and response events.

By the way, it's not a good practice to put the upload progress handling in the HttpInterceptor, as it's effect is project wide, i.e. every request you make you make will go through the interceptor. And you don't need the progress handling in every request, or do you?

Community
  • 1
  • 1
Envil
  • 2,687
  • 1
  • 30
  • 42
  • I agree, I put there just for testing because my http callers are not reporting progress, removing the whole code block and returning `next.handle(cloneReq)` doesn't solve the problem. my http caller is still not reporting the progress. I will change it to `tap` instead of `mergeMap` – JSON Jul 02 '18 at 08:19
  • @JSON so you meant without the interceptor the code still doesn't work? – Envil Jul 02 '18 at 08:26
  • I meant by removing the block is removing the pipe. and yes the http caller " `public upload(apiUrl: string, jsonData: {} = {})` " is still not reporting the progress. – JSON Jul 02 '18 at 08:29
  • I guest maybe the way you're performing the request is incorrect, please refer to https://angular.io/guide/http#listening-to-progress-events You should create an `HttpRequest` then call `this.http.request(req)` instead of `this.http.post(...)` – Envil Jul 02 '18 at 08:34
  • You nailed it, so it worked by changing from `post` to `request`, but what is the difference? – JSON Jul 02 '18 at 08:44