angularfile-uploaduploadangular-httpclientangular-httpclient-interceptors

Can get upload progress event in HttpInterceptor but not from HttpClient call?


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


Solution

  • 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?