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
相关产品推荐
相关产品推荐

