You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Angular中通过multipart/form-data实现包含图片的表单上传功能?

问题修复方案

现有代码存在3个核心错误导致后端无法识别文件:

  1. ngModel 不支持绑定 <input type="file"> 的文件对象,menu.image 实际未存储有效文件
  2. 带文件的表单提交需使用 FormData 格式,你当前是直接序列化JSON提交,无法传递二进制文件
  3. 手动设置 Content-Type: multipart/form-data 会缺失请求所需的边界标识符,导致后端解析失败

1. 修改表单模板

移除文件输入的ngModel绑定,通过change事件捕获选中的文件:

<form #createMenu="ngForm" (ngSubmit)="onSubmit(createMenu)" style="border: 1px solid; padding: 20px; display:flex; justify-content:center; flex-direction: column;" enctype="multipart/form-data">
    <mat-form-field appearance="fill">
        <mat-label>Title</mat-label>
        <input matInput placeholder="example: Pizza" name="title" #title="ngModel" [(ngModel)]="menu.title" required>
    </mat-form-field>
    <mat-form-field appearance="fill">
        <mat-label>Description</mat-label>
        <textarea matInput name="description" placeholder="example: All of our pizzas are amazing"  #description="ngModel" [(ngModel)]="menu.description" required></textarea>
    </mat-form-field>
        <br>
    <label>Image of menu *</label>  
   <!-- 移除ngModel绑定,新增change事件 -->
   <input type="file" name="image" placeholder="example: All of our pizzas are amazing" required (change)="onFileSelected($event)"/>
    <br>
    <input type="submit" class="submit" value="SEND"
    [disabled]="!createMenu.form.valid || !selectedFile" style="border:none; background:#181818; height: 40px; color: #f1f1f1; font-size: 22px;" />
</form>

2. 修改组件代码

新增变量存储选中的文件,提交时构造FormData传递给服务:

public status: string;
public menu: Menu;
// 新增变量存储选中的文件
public selectedFile: File | null = null;

constructor(private _AdminmenuService:AdminmenuService) {
  this.status = "";
  this.menu = new Menu(1, '', '', '');
 }

// 新增文件选择处理方法
onFileSelected(event: any) {
  if (event.target.files.length > 0) {
    this.selectedFile = event.target.files[0];
  }
}

onSubmit(form:any){
  // 构造FormData
  const formData = new FormData();
  formData.append('title', this.menu.title);
  formData.append('description', this.menu.description);
  formData.append('image', this.selectedFile as File, this.selectedFile?.name);

  this._AdminmenuService.create(formData).subscribe(
    response => {
      this.status = response.status;
      if (response.status == "success") {
        form.reset();
        // 清空选中的文件
        this.selectedFile = null;
      }
    },
    error => {
      console.log(error);
    }
  );
}

3. 修改服务代码

移除JSON序列化逻辑,删除手动设置的multipart/form-data请求头:

create(formData: FormData):Observable<any>{
  const headerDict  = {
    'Authorization': 'Bearer '+localStorage.getItem('token'),
    'X-Requested-With': 'XMLHttpRequest',
  }

  const requestOptions = {                                                                                                                                                                                 
    headers: new HttpHeaders(headerDict), 
  };

  return this._http.post(this.url+'menu/create', formData, requestOptions);
}

注意事项

  • 确保FormData中文件字段的键名(上述代码中为image)和你Postman测试时用的字段名完全一致
  • 不需要修改Menu类的定义,提交阶段改用FormData封装参数即可

内容的提问来源于stack exchange,提问作者Jagcweb

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.04 06:36:00