文件上传进度检查文件是否在 Angular 7 中作为 FormData 发送?
File upload progress checking if file send as FormData in Angular 7?
我使用 HttpClient
作为 http
:
将文件上传为 Angular 7 中的 FormData
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) {
// ...
}
这里的主要问题是没有检查上传,因为文件是上传的一部分 FormData
所以在上传完成之前我没有得到任何反馈。
我对这个进度检查有点困惑。我必须将文件上传为 FormData。这种情况下如何查看上传进度?
已编辑:
由于 Angular grows ,正如我在之前的回答中所建议的那样 - npm 包不适合您的需求。所以这是您实际可以做的事情:
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}.`;
}
}
然后您可以根据 getEventMessage() 的返回值修改您的 showProgress() 函数。这有帮助吗?
答案在于HttpClient
的实施。通过 HttpClient.post
方法创建的所有请求默认 observe
属性 为 body
。参见 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(强调我的):
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 an Observable<HttpResponse<T>>
where the T parameter of HttpResponse depends on the responseType and any optionally provided type parameter. A value of body will return an Observable<T>
with the same T body type.
文档还指出,如果您将 HttpRequest
实例传递给 request
,它将 return 默认情况下 HttpEvent
流的可观察对象:
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.
因此,观察 HttpEvent
流的最简单方法是直接传递一个 HttpRequest
对象,如前所述:
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);
}
我在本地存储库上测试了这个重构代码,它工作得很好。
我使用 HttpClient
作为 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) {
// ...
}
这里的主要问题是没有检查上传,因为文件是上传的一部分 FormData
所以在上传完成之前我没有得到任何反馈。
我对这个进度检查有点困惑。我必须将文件上传为 FormData。这种情况下如何查看上传进度?
已编辑:
由于 Angular grows ,正如我在之前的回答中所建议的那样 - npm 包不适合您的需求。所以这是您实际可以做的事情:
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}.`;
}
}
然后您可以根据 getEventMessage() 的返回值修改您的 showProgress() 函数。这有帮助吗?
答案在于HttpClient
的实施。通过 HttpClient.post
方法创建的所有请求默认 observe
属性 为 body
。参见 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(强调我的):
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.
文档还指出,如果您将 HttpRequest
实例传递给 request
,它将 return 默认情况下 HttpEvent
流的可观察对象:
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.
因此,观察 HttpEvent
流的最简单方法是直接传递一个 HttpRequest
对象,如前所述:
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);
}
我在本地存储库上测试了这个重构代码,它工作得很好。