问题
I uploading file as FormData in Angular 7 with this code using HttpClient
as http
:
sendImageFile(subUri: string, id: number, fileToUpload: File): Observable<any> {
const formData: FormData = new FormData();
formData.append('file', fileToUpload, fileToUpload.name);
formData.append('photoalbum_id', id.toString() );
// ... some other .append()
const customHeaders = new HttpHeaders({
'Authorization': 'Bearer' + localStorage.getItem('token'),
'Accepted-Encoding': 'application/json'
});
const customOptions = {
headers: customHeaders,
reportProgress: true
};
return this.http.post(this.url, formData, customOptions)
.pipe(
map( (event: HttpEvent<any>) => this.getEventMessage(event, fileToUpload)),
tap(message => this.showProgress(message)),
// last(),
catchError(this.handleError));
}
private showProgress(message: any) {
// ...
}
private getEventMessage(event: HttpEvent<any>, file: File) {
// ...
}
The main problem is here isn't checking the uploading because the file is uploaded part of the FormData
so I don't get any feedback until the upload is finished.
I'm a little bit confused about this progress checking. I must to upload file as FormData. How can I check the upload progress in this case?
回答1:
The answer lies in HttpClient
's implementation. All requests created via the HttpClient.post
method default the observe
property to body
. See this HttpClient.post method for details. What this means is: even though you successfully set reportProgress
to true
, the resulting observable is observing the request body instead of the HttpEvents
. From the docs (emphasis mine):
The observe value determines the return type of request(), based on what the consumer is interested in observing. A value of events will return an
Observable<HttpEvent>
representing the raw HttpEvent stream, including progress events by default. A value of response will return anObservable<HttpResponse<T>>
where the T parameter of HttpResponse depends on the responseType and any optionally provided type parameter. A value of body will return anObservable<T>
with the same T body type.
The documentation also notes that if you pass an HttpRequest
instance to request
, it will return an observable of the HttpEvent
stream by default:
This method 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.
So, the easiest way to observe the HttpEvent
stream is to pass an HttpRequest
object directly as noted:
sendImageFile(subUri: string, id: number, fileToUpload: File): Observable<any> {
const formData: FormData = new FormData();
formData.append('file', fileToUpload, fileToUpload.name);
formData.append('photoalbum_id', id.toString());
// ... some other .append()
const customHeaders = new HttpHeaders({
'Authorization': 'Bearer' + localStorage.getItem('token'),
'Accepted-Encoding': 'application/json'
});
const customOptions = {
headers: customHeaders,
reportProgress: true,
};
const req = new HttpRequest('POST', this.url, formData, customOptions);
// Call HttpClient.request with an HttpRequest as only param to get an observable of HttpEvents
return this.http.request(req)
.pipe(
map((event: HttpEvent<any>) => this.getEventMessage(event)),
catchError(this.handleError));
}
private getEventMessage(event: HttpEvent<any>) {
// We are now getting events and can do whatever we want with them!
console.log(event);
}
I tested this refactored code on a local repository and it worked just fine.
回答2:
EDITED :
Due to the fact that Angular grows , as I proposed in my previous answer - the npm package would not suit your needs. So here is what you can actually do :
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}.`;
}
}
and then you can modify your showProgress() function according to the returned values of getEventMessage() . Does this help ?
来源:https://stackoverflow.com/questions/54062262/file-upload-progress-checking-if-file-send-as-formdata-in-angular-7