Java中@MultipartForm发送多部件表单参数报400错误排查
问题分析与解决方案
问题描述
在Java中使用Resteasy客户端通过@MultipartForm发送多部件文件及表单参数到Spring服务器时,收到400 Bad Request错误,服务器抛出org.springframework.web.multipart.support.MissingServletRequestPartException: Required request part 'file' is not present。
服务器端接口
@RequestMapping(value = "doSomething", method = RequestMethod.POST, headers = {"content-type=multipart/mixed","content-type=multipart/form-data"}, produces = MediaType.TEXT_PLAIN_VALUE) ResponseEntity<String> doSomething( @RequestPart("name") String name, @RequestPart("file") MultipartFile file, @RequestPart("type") String type );
客户端接口
@POST @Path("doSomething") @Produces(MediaType.TEXT_PLAIN) @Consumes(MediaType.MULTIPART_FORM_DATA) String doSomething(@MultipartForm MultipartBody body);
客户端MultipartBody类
public class MultipartBody { @FormParam("name") @PartType(MediaType.TEXT_PLAIN) public String name; @FormParam("file") @PartType(MediaType.APPLICATION_OCTET_STREAM) public InputStream file; @FormParam("type") @PartType(MediaType.TEXT_PLAIN) public String type; }
客户端请求体内容
Body: --02d16fb7-e89e-4847-adaa-d64db0c86700 Content-Disposition: form-data; name="file" Content-Type: application/octet-stream testerito --02d16fb7-e89e-4847-adaa-d64db0c86700 Content-Disposition: form-data; name="name" Content-Type: text/plain test --02d16fb7-e89e-4847-adaa-d64db0c86700 Content-Disposition: form-data; name="type" Content-Type: text/plain test --02d16fb7-e89e-4847-adaa-d64db0c86700--
问题原因
- 服务器端headers配置错误:
当前headers = {"content-type=multipart/mixed","content-type=multipart/form-data"}要求请求同时满足这两个Content-Type条件,这是不可能的,导致请求无法正确匹配接口,或Spring解析时出现异常。 - 客户端file请求部分缺少filename属性:
Spring的@RequestPart("file") MultipartFile要求对应的请求部分在Content-Disposition头中包含filename参数,否则Spring无法将其识别为文件类型的请求部分,从而抛出缺失file部件的异常。
解决方案
1. 修复服务器端接口配置
将headers替换为consumes属性,正确指定支持的多部件类型:
@RequestMapping(value = "doSomething", method = RequestMethod.POST, consumes = {MediaType.MULTIPART_FORM_DATA_VALUE, MediaType.MULTIPART_MIXED_VALUE}, produces = MediaType.TEXT_PLAIN_VALUE) ResponseEntity<String> doSomething( @RequestPart("name") String name, @RequestPart("file") MultipartFile file, @RequestPart("type") String type );
如果仅需支持multipart/form-data,可简化为consumes = MediaType.MULTIPART_FORM_DATA_VALUE。
2. 修复客户端请求,让file部分携带filename
以下三种方式任选其一:
方式一:修改MultipartBody,手动添加Content-Disposition头
public class MultipartBody { @FormParam("name") @PartType(MediaType.TEXT_PLAIN) public String name; // 为file部件添加包含filename的Content-Disposition头 @HeaderParam("Content-Disposition") @FormParam("file") public String fileDisposition = "form-data; name=\"file\"; filename=\"your-file-name.txt\""; @FormParam("file") @PartType(MediaType.APPLICATION_OCTET_STREAM) public InputStream file; @FormParam("type") @PartType(MediaType.TEXT_PLAIN) public String type; }
方式二:将InputStream替换为File类型(Resteasy自动处理filename)
public class MultipartBody { @FormParam("name") @PartType(MediaType.TEXT_PLAIN) public String name; @FormParam("file") @PartType(MediaType.APPLICATION_OCTET_STREAM) public File file; // 使用File类型时,Resteasy会自动添加filename参数 @FormParam("type") @PartType(MediaType.TEXT_PLAIN) public String type; }
方式三:使用MultipartFormDataOutput手动构建请求(更灵活)
直接构建多部件请求体,无需实体类:
MultipartFormDataOutput output = new MultipartFormDataOutput(); output.addFormData("name", "test", MediaType.TEXT_PLAIN_TYPE); output.addFormData("type", "test", MediaType.TEXT_PLAIN_TYPE); // 添加文件时指定filename output.addFormData("file", new FileInputStream("/path/to/your/file"), MediaType.APPLICATION_OCTET_STREAM_TYPE, "test.txt"); // 发送请求 Response response = resteasyClient.target("your-api-url") .request(MediaType.TEXT_PLAIN) .post(Entity.entity(output, MediaType.MULTIPART_FORM_DATA));
内容的提问来源于stack exchange,提问作者Julian
相关产品推荐
相关产品推荐

