HttpRequest and reportProgress not working or messing up my requests
Asked Answered
P

7

6

I am implementing a file upload service with Angular 5 and I want to give the user some feedback on the upload progress. I found several pages suggesting to use the reportProgress parameter that comes with Angulars HttpClient, but I cannot get it working.

I use a wrapper class for all my http-requests, which then does some logic and finally all requests end up in the same method that's being called:

public request(request: HttpRequest<any>, options?: any): Observable<any> {
  return this.httpClient.request(request.method, request.url, {
    body: request.body,
    headers: request.headers,
    responseType: request.responseType,
    ...options
  });
}

I then pass a upload (post) call to it, with { reportProgress: true } as options. This did not work at all, nothing on the request changed. So I suspected, that I actually need to use the reportProgress-parameter in the HttpRequest constructor to make it work and changed my code accordingly:

public request(request: HttpRequest<any>, options?: any): Observable<any> {
  return this.httpClient.request(
    new HttpRequest(request.method, request.url, request.body, {
      headers: request.headers,
      responseType: request.responseType,
      ...options
    })
  );
}

This leads to the even more weird behavior, that now no matter what my options look like, I always only receive {type: 0} as response from the request.

What am I overseeing? I use Angular 5.1.1 and I am really a bit puzzled here right now.

So to give an explicit example, right now I receive the same response for those two HttpRequests:

{  
  "url":"http://127.0.0.1:8888/test",
  "body":{  
   "data":"testdata"
  },
  "reportProgress":false,
  "withCredentials":false,
  "responseType":"json",
  "method":"POST",
  "headers":{ some-headers ... }
}

and this request:

{  
  "url":"http://127.0.0.1:8888/api/pages",
  "body":{  
    "pageUrl":"http://localhost:1234/"
  },
  "reportProgress":true,
  "withCredentials":false,
  "responseType":"json",
  "method":"POST",
  "headers":{ some-headers ... }
}
Polite answered 16/4, 2018 at 14:53 Comment(2)
Why are you using a wrapper class rather than an interceptor? Also note that the .clone method is probably a better way to create a new request based on an existing one.Weigela
Because it's been a while that the wrapper has been written and there has not been time yet to rewrite it. I am aware of the .clone()-method, but wanted a generic approach, where I do not have to check for single properties in the option-object.Polite
P
4

I solved the issues. There were actually two things that were involved in the behavior described in the question.

First of all ... rtfm! https://angular.io/api/common/http/HttpClient

This method [HttpClient.request()] can be called in one of two ways. Either an HttpRequest instance can be passed directly as the only parameter, or a method can be passed as the first parameter, a string URL as the second, and an options hash as the third.

If a HttpRequest object is passed directly, an Observable of the raw HttpEvent stream will be returned.

This explains why my two request (both passed as HttpRequest returned {type: 0} from now on, regardless of the reportProgress-paramter being true or false.

Only receiving the SENT-event ({type: 0}) on the other hand was a missconfiguration of the backend itself.

Polite answered 18/4, 2018 at 12:54 Comment(3)
Can you add more detail about how you solved the issue?Unfolded
In the documentation you can find more details: "The observe value determines the return type, according to what you are interested in observing" 1) An observe value of events returns an observable of the raw HttpEvent stream, including progress events by default. 2) An observe value of response returns an observable of HttpResponse<T>, where the T parameter depends on the responseType and any optionally provided type parameter. 3) An observe value of body returns an observable of <T> with the same T body type.Sissie
what was the misconfig in the backend? do we need any special handling in the backend?Vilmavim
S
11

along with {reportProgress: true} you would need to send {observe: 'events'}

this.httpClient.post(environment.uploadDocument, file, { reportProgress: true, observe: 'events' })
.subcribe(data =>{
if (data['type'] === HttpEventType.UploadProgress) {
   console.log('loaded ', data['loaded'], '   total  -', data['total']);
   }
})
Skiagraph answered 24/4, 2019 at 19:56 Comment(2)
observe: "events" makes the file corruptFlagitious
I have been using the same. Works good for me. If you could share more details regarding you project.Skiagraph
C
6

This method may help

public progress: number = 0;
public message: string = "";

constructor(private http: HttpClient) {}

onSubmit() {
    // replace with your request data
    const formModel = this.userForm.value;
    let formData = new FormData();

    formData.append("upload", formModel.upload);

    const uploadReq = new HttpRequest('POST', 'api/Upload', formData, {
        reportProgress: true,
    });

    this.http.request(uploadReq).subscribe((event) => {
        if (event.type === HttpEventType.UploadProgress) {
            this.progress = Math.round(100 * event.loaded / event.total);
        }
        else if (event.type === HttpEventType.Response) {
            this.message = event.body.toString();
        }
    });
}
Chobot answered 16/4, 2018 at 15:38 Comment(2)
sorry, but this is just the first snippet you find when googling how to track upload progess with angular (which I already found: "I found several pages suggesting to use the reportProgress parameter"). The answer does not give any input on my actual question ...Polite
@newnoise, it's what I'm currently using and it works; even if it is the first result in Google.Chobot
P
4

I solved the issues. There were actually two things that were involved in the behavior described in the question.

First of all ... rtfm! https://angular.io/api/common/http/HttpClient

This method [HttpClient.request()] can be called in one of two ways. Either an HttpRequest instance can be passed directly as the only parameter, or a method can be passed as the first parameter, a string URL as the second, and an options hash as the third.

If a HttpRequest object is passed directly, an Observable of the raw HttpEvent stream will be returned.

This explains why my two request (both passed as HttpRequest returned {type: 0} from now on, regardless of the reportProgress-paramter being true or false.

Only receiving the SENT-event ({type: 0}) on the other hand was a missconfiguration of the backend itself.

Polite answered 18/4, 2018 at 12:54 Comment(3)
Can you add more detail about how you solved the issue?Unfolded
In the documentation you can find more details: "The observe value determines the return type, according to what you are interested in observing" 1) An observe value of events returns an observable of the raw HttpEvent stream, including progress events by default. 2) An observe value of response returns an observable of HttpResponse<T>, where the T parameter depends on the responseType and any optionally provided type parameter. 3) An observe value of body returns an observable of <T> with the same T body type.Sissie
what was the misconfig in the backend? do we need any special handling in the backend?Vilmavim
R
3

After reading https://mcmap.net/q/460960/-how-to-use-reportprogress-in-httpclient-in-angular-duplicate I added the observe: 'events' parameter and started receiving the HttpEvents in my subscription.

Representation answered 19/4, 2019 at 17:54 Comment(0)
A
2

if You Are using service worker you have to send ngsw-bypass header.

example:-

file: File;

uploadProgress: number;

constructor(private http: HttpClient) { }

uploadData(): void {

    const formData = new FormData();
    formData.append('file', this.file);


    const headers = new HttpHeaders({ 'ngsw-bypass': '' });

    this.http.post(`upload url`, formData, {
      reportProgress: true,
      observe: 'events',
      headers
    }).subscribe(event => {

            if (event.type === HttpEventType.UploadProgress) {
                this.uploadProgress = Math.round(100 * event.loaded / event.total);
            }
            else if (event.type === HttpEventType.Response) {
                console.log(event.body);
            }

        });
  }
Arruda answered 8/9, 2021 at 10:22 Comment(0)
I
1
return this.http.request('POST', api_enpoint , { body: body, headers: headers, reportProgress: true, withCredentials: true }).map(httpResponse => {
   console.log(httpResponse);
});

Instead of passing the httpRequest object, you need to pass the request in this fashion (works for both http as well for https)

Idolatrize answered 25/10, 2018 at 7:27 Comment(0)
A
0

Upload the formdata along with header details

This snipet will help ou to upload formdata and while subscribe you can implement the progress bar as well

uploadMyImage(formData: any) {
    const httpOptions = new HttpHeaders({
      'Content-Type': 'multipart/form-data', 'boundary': 'something'
      });
    return this.http.post('http://localhost:4000/api/upload', formData, { reportProgress: true, observe: 'events', headers: httpOptions });
  }
Antipus answered 5/11, 2019 at 15:17 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.