AngularJS向Spring Boot发送带图片对象时提示非multipart请求异常
问题根因
报错由两处代码错误直接导致:
- 后端参数注解使用逻辑错误:
multipart/form-data请求不支持同时使用@RequestBody和@RequestParam接收参数。@RequestBody会消费整个请求输入流做JSON反序列化,会直接破坏multipart请求的分片解析流程,导致Spring无法识别这是一个multipart请求。 - 前端请求构造错误:你仅将文件放入了FormData实例,最终发请求时传递的是普通JS对象
{file, personRequest},Angular HttpClient会默认将这类普通对象编码为application/json格式,请求根本不是multipart类型,自然抛出对应异常。另外手动设置Content-Type: multipart/form-data头的操作本身也是错误的,会丢失浏览器自动生成的boundary分隔符,同样会导致解析失败。
修复步骤
1. 调整后端Controller代码
将@RequestBody替换为专门处理multipart分片的@RequestPart注解,该注解支持自动将multipart中JSON格式的分片反序列化为Java对象,修改后代码如下:
@PostMapping("multi") public String multi(@RequestParam MultipartFile file, @RequestPart PersonRequest personRequest) throws IOException { Binary fileBinary = new Binary(file.getBytes()); log.info("接收文件: {}, 接收业务参数: {}", file.getOriginalFilename(), personRequest); // 直接将fileBinary设置到关联实体对象中,完成入库等后续逻辑 return "success"; }
如果上述写法在你的Spring版本中存在兼容性问题,可以用更稳妥的兼容方案:接收JSON字符串参数后手动反序列化:
@PostMapping("multi") public String multi(@RequestParam MultipartFile file, @RequestParam String personRequest) throws IOException { Binary fileBinary = new Binary(file.getBytes()); // 用Spring Boot内置的Jackson将JSON字符串转为PersonRequest对象 PersonRequest req = new ObjectMapper().readValue(personRequest, PersonRequest.class); log.info("接收文件: {}, 接收业务参数: {}", file.getOriginalFilename(), req); return "success"; }
2. 调整前端Angular请求代码
核心要求:所有参数必须追加到同一个FormData实例中,直接传递FormData实例作为请求体,不要手动设置Content-Type请求头。
如果后端用@RequestPart的写法,前端需要将业务对象包装为JSON类型的Blob再追加到FormData,保证后端可以正确识别分片的内容类型:
addPersonWithIMG(image:File, personRequest: PersonRequest):Observable<any>{ const formData = new FormData(); // 追加文件参数,参数名和后端@RequestParam声明的参数名保持一致 formData.append('file', image); // 将业务对象转为JSON Blob,指定内容类型为application/json const reqBlob = new Blob([JSON.stringify(personRequest)], { type: 'application/json' }); formData.append('personRequest', reqBlob); // 直接传递formData作为请求体,不要设置任何自定义Content-Type头 return this.http.post(`${this.baseUrl}/multi`, formData); }
如果后端用兼容的字符串参数接收方案,直接追加JSON字符串即可:
addPersonWithIMG(image:File, personRequest: PersonRequest):Observable<any>{ const formData = new FormData(); formData.append('file', image); formData.append('personRequest', JSON.stringify(personRequest)); return this.http.post(`${this.baseUrl}/multi`, formData); }
验证要点
改完后可以在浏览器开发者工具的网络面板查看请求头,正常的请求头会自动带Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryxxxx格式的内容,不存在boundary缺失、Content-Type为application/json的情况,后端可以同时拿到文件和业务参数,不会再抛出原异常。
另外注意:你DTO里注释掉的private Binary image字段不需要保留,文件已经通过MultipartFile单独接收,拿到字节数组后直接转Binary存入实体即可,不需要前端传递Binary类型字段。
内容的提问来源于stack exchange,提问作者Robs
相关产品推荐
相关产品推荐

