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

OkHttp转Spring RestTemplate多文件请求:请求体文件无法识别

问题:RestTemplate发送Multipart表单文件无法被识别

原本用OkHttp可以正常从项目资源目录读取文件并以Multipart表单发送POST请求,但转换成Spring RestTemplate后,请求体中的文件无法被服务端识别。

OkHttp 实现代码

public String createImageEditWithOkHttp(String prompt) throws IOException
{
    OkHttpClient client = new OkHttpClient().newBuilder()
            .connectTimeout(30, TimeUnit.SECONDS)
            .callTimeout(30, TimeUnit.SECONDS)
            .readTimeout(30, TimeUnit.SECONDS)
            .writeTimeout(30, TimeUnit.SECONDS)
            .build();
    RequestBody body = new MultipartBody.Builder().setType(MultipartBody.FORM)
            .addFormDataPart("image","file",
                    RequestBody.create(MediaType.parse("application/octet-stream"),
                            ResourceUtils.getFile("classpath:image_edit_original.png")))
            .addFormDataPart("mask","file",
                    RequestBody.create(MediaType.parse("application/octet-stream"),
                            ResourceUtils.getFile("classpath:image_edit_mask.png")))
            .addFormDataPart("prompt",prompt)
            .addFormDataPart("n","1")
            .addFormDataPart("size", ImageSize.SMALL.getSize())
            .build();
    Request request = new Request.Builder()
            .url(IMAGE_EDIT_URL)
            .method("POST", body)
            .addHeader("Authorization", "Bearer " + OPENAI_API_KEY)
            .build();
    Response response = client.newCall(request).execute();

    return response.body().string();
}

RestTemplate 原实现代码

public String createImageEditWithRestTemplate(String prompt) throws FileNotFoundException
{
    HttpEntity<MultiValueMap<String, Object>> requestEntity
            = new HttpEntity<>(createBody(prompt), commonHttpHeaders());

    ResponseEntity<String> response = restTemplate.postForEntity(IMAGE_EDIT_URL, requestEntity, String.class);

    return response.getBody();
}

private MultiValueMap<String, Object> createBody(String prompt) throws FileNotFoundException
{
    MultiValueMap<String,Object> body = new LinkedMultiValueMap<>();

    body.add("image", ResourceUtils.getFile("classpath:image_edit_original.png"));
    body.add("mask", ResourceUtils.getFile("classpath:image_edit_mask.png"));
    body.add("prompt",prompt);
    body.add("n","1");
    body.add("size", ImageSize.SMALL.getSize());

    return body;
}

private HttpHeaders commonHttpHeaders()
{
    MultiValueMap<String,String> headers = new LinkedMultiValueMap<>();

    headers.add("Authorization", "Bearer " + OPENAI_API_KEY);
    headers.add("Content-Type", org.springframework.http.MediaType.MULTIPART_FORM_DATA_VALUE);

    return new HttpHeaders(headers);
}

解决方案

1. 使用ClassPathResource封装资源文件

RestTemplate处理Multipart表单时,需要用Spring的资源类(如ClassPathResource)封装文件,而非直接传入File对象。这样才能正确生成包含文件名、Content-Type的Multipart部分,同时避免JAR包部署时的文件路径问题。

修改createBody方法:

private MultiValueMap<String, Object> createBody(String prompt) {
    MultiValueMap<String,Object> body = new LinkedMultiValueMap<>();

    // 直接用ClassPathResource读取类路径下的资源,无需捕获FileNotFoundException
    body.add("image", new ClassPathResource("image_edit_original.png"));
    body.add("mask", new ClassPathResource("image_edit_mask.png"));
    body.add("prompt", prompt);
    body.add("n", "1");
    body.add("size", ImageSize.SMALL.getSize());

    return body;
}

2. 移除手动设置的Content-Type头

RestTemplate在处理MultiValueMap请求体时,会自动通过MultipartFormHttpMessageConverter生成包含正确boundary的multipart/form-data头。手动设置该头会覆盖自动生成的内容,导致服务端无法解析Multipart表单。

修改commonHttpHeaders方法:

private HttpHeaders commonHttpHeaders() {
    HttpHeaders headers = new HttpHeaders();
    headers.add("Authorization", "Bearer " + OPENAI_API_KEY);
    // 移除手动设置的Content-Type,由RestTemplate自动处理
    return headers;
}

3. 确保RestTemplate配置了MultipartFormHttpMessageConverter

如果是手动创建RestTemplate实例,需要显式注册MultipartFormHttpMessageConverter,否则无法处理Multipart请求。配置示例:

@Bean
public RestTemplate restTemplate() {
    RestTemplate restTemplate = new RestTemplate();
    // 添加Multipart表单转换器
    restTemplate.getMessageConverters().add(new MultipartFormHttpMessageConverter());
    // 配置超时时间,对齐OkHttp的30秒设置
    SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
    factory.setConnectTimeout(30000);
    factory.setReadTimeout(30000);
    restTemplate.setRequestFactory(factory);
    return restTemplate;
}

Spring Boot自动配置的RestTemplate默认已包含该转换器,手动创建时需添加。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 02:38:12