文件上传进度检查文件是否在 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);
}

我在本地存储库上测试了这个重构代码,它工作得很好。