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

Spring Boot中RestTemplate消费multipart/form-data时的文件参数问题

在Spring中正确传递multipart/form-data的文件ContentType、文件名及内容

我来帮你搞定这个RestTemplate调用multipart接口的问题!你之前的两种写法都踩了坑,导致返回400 Bad Request,咱们一步步来修正。

先说说你之前写法的问题

  • 代码示例1:直接把字节数组丢进MultiValueMap,Spring没法识别这是一个文件part,自然没法帮你设置正确的Content-Type和文件名,接口接收方解析失败就返回400了。
  • 代码示例2:手动拼接Content-Disposition和Content-Type到key里,还手动指定了boundary,这完全打乱了Spring自动处理multipart请求的逻辑——Spring本来会自动生成合法的boundary、正确组装每个part的请求头,你手动干预后请求格式就乱了,接口自然不认。

正确的实现方式

Spring的RestTemplate处理multipart请求时,每个文件part需要单独封装成HttpEntity,通过它来设置该文件的Content-Type、文件名等信息,再用ByteArrayResource(或FileSystemResource)包装文件内容。

针对字节数组的场景(你的案例)

import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.http.ContentDisposition;

// 1. 构建全局请求头
HttpHeaders globalHeaders = new HttpHeaders();
globalHeaders.add("Token", "_45378ffb-e366-45ec-9ac4-eb968c57aee3");
globalHeaders.setContentType(MediaType.MULTIPART_FORM_DATA);

// 2. 构建文件part的专属请求头
String filename = "你的文件名.txt"; // 替换成实际文件名
HttpHeaders filePartHeaders = new HttpHeaders();
filePartHeaders.setContentType(MediaType.APPLICATION_OCTET_STREAM); // 设置文件的Content-Type
// 设置Content-Disposition:指定表单字段名(name要和接口要求的一致)、文件名
ContentDisposition fileDisposition = ContentDisposition.builder("form-data")
        .name("file") // 注意!这里是接口要求的表单字段名,比如接口期望文件在"file"这个key下
        .filename(filename)
        .build();
filePartHeaders.setContentDisposition(fileDisposition);

// 3. 用ByteArrayResource包装文件字节内容,重写getFilename确保Spring识别文件名
ByteArrayResource fileResource = new ByteArrayResource(msg.getBytes()) {
    @Override
    public String getFilename() {
        return filename;
    }
};
// 把文件内容和专属头包装成HttpEntity
HttpEntity<ByteArrayResource> fileEntity = new HttpEntity<>(fileResource, filePartHeaders);

// 4. 构建其他表单参数(比如OrderRequest)
HttpEntity<String> orderRequestEntity = new HttpEntity<>(message);

// 5. 组装所有请求part到MultiValueMap
MultiValueMap<String, Object> requestBody = new LinkedMultiValueMap<>();
requestBody.add("file", fileEntity); // 这里的key要和上面fileDisposition里的name一致
requestBody.add("OrderRequest", orderRequestEntity);

// 6. 发送请求
RestTemplate restTemplate = new RestTemplate();
HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(requestBody, globalHeaders);
ResponseEntity<String> response = restTemplate.postForEntity(url, requestEntity, String.class);

针对本地文件的场景(如果是读取本地文件上传)

如果你的文件是本地磁盘文件,可以用FileSystemResource替代ByteArrayResource,更简便:

import org.springframework.core.io.FileSystemResource;
import java.io.File;

File localFile = new File("/path/to/your/local/file");
FileSystemResource fileResource = new FileSystemResource(localFile);

// 后续的请求头构建、组装逻辑和上面一致
HttpHeaders filePartHeaders = new HttpHeaders();
filePartHeaders.setContentType(MediaType.APPLICATION_OCTET_STREAM);
ContentDisposition fileDisposition = ContentDisposition.builder("form-data")
        .name("file")
        .filename(localFile.getName())
        .build();
filePartHeaders.setContentDisposition(fileDisposition);

HttpEntity<FileSystemResource> fileEntity = new HttpEntity<>(fileResource, filePartHeaders);

关键注意点

  1. 表单字段名要匹配:ContentDisposition.builder里的name参数,必须和接口文档要求的文件字段名一致(比如接口可能要求用uploadFile而不是file),这是很多人踩坑的点。
  2. 不要手动设置boundary:全局请求头里只需要设置MediaType.MULTIPART_FORM_DATA,Spring会自动生成合法的boundary,手动设置反而会导致请求格式错误。
  3. 文件资源必须返回文件名:不管用ByteArrayResource还是FileSystemResource,都要确保getFilename()能返回正确的文件名,这样Spring才能在请求头里正确带上文件名信息。

这样处理后,你的请求就会符合multipart/form-data的规范,接口就能正确解析文件的ContentType、文件名和内容了,不会再返回400错误啦。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 06:44:01