文件上传进度检查文件是否在Angular 7中作为FormData发送?

时间:2019-01-06 14:03:13

标签: angular file-upload multipartform-data angular7 form-data

我使用以下代码将Angular 7中的文件作为FormData上载为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。在这种情况下如何检查上传进度?

2 个答案:

答案 0 :(得分:8)

答案在于HttpClient的实现。通过HttpClient.post方法创建的所有请求都将observe属性的默认值为body。参见this HttpClient.post method for details。这意味着:即使您成功地将reportProgress设置为true,所产生的observable仍在观察请求正文,而不是HttpEvents。来自the docs(重点是我):

  

观察值根据消费者感兴趣的观察值确定request()的返回类型。 事件值将返回代表原始HttpEvent流的Observable<HttpEvent> ,默认情况下包括进度事件。 response的值将返回Observable<HttpResponse<T>>,其中HttpResponse的T参数取决于responseType和任何可选提供的type参数。 主体的值将返回具有相同T主体类型的Observable<T>

文档还指出,如果将HttpRequest实例传递给request,则默认情况下它将返回HttpEvent流的可观察对象:

  

可以用以下两种方法之一调用此方法。可以直接将Ht​​tpRequest实例作为唯一参数传递,或者可以将方法作为第一个参数传递,将字符串URL作为第二个参数,将选项哈希作为第三个参数。

     

如果直接传递HttpRequest对象,则将返回原始HttpEvent流的Observable。

因此,观察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);
}

我在本地存储库上测试了此重构的代码,并且工作正常。

答案 1 :(得分:3)

已编辑:
由于Angular不断增长,正如我在上一个答案中所建议的那样-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()函数。这有帮助吗?