使用Spring WebClient上传Multipart文件调用REST API报错求助
我有一个使用Spring WebClient调用REST API的场景,需在请求中传递图片或PDF文件。我通过内部方法downloadFile()获取到File类型的文件,当前采用如下方式传输文件:
File file = downloadFile(key); InputStream stream = new FileInputStream(file); MultipartFile multipartFile = new MockMultipartFile(file.getName(), file.getName(), "multipart/form-data", stream); JsonNode response = Objects.requireNonNull(webClient.post() .uri("/api/{groupId}/images", uriBuilder -> uriBuilder .queryParam("referenceId", referenceId) .build(Map.of("groupId", 1000))) .header(HttpHeaders.AUTHORIZATION, "Bearer " + auth2Service.getAccessToken()) .bodyValue(multipartFile) .retrieve() .bodyToMono(JsonNode.class) .block());
但出现如下错误:
"Type definition error: [simple type, class java.io.ByteArrayInputStream]; nested exception is com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class java.io.ByteArrayInputStream and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) (through reference chain: org.springframework.mock.web.MockMultipartFile["inputStream"])"
请问我当前的文件发送方式是否正确?若正确,该错误的原因是什么?
- 当前的文件发送方式不正确,错误原因及修正方案如下:
错误原因:
使用bodyValue()传递MockMultipartFile时,WebClient会默认用Jackson序列化该对象,但MockMultipartFile内部的ByteArrayInputStream没有对应的Jackson序列化器,导致序列化失败抛出上述错误。且bodyValue()并不适合构建multipart/form-data类型的请求。正确的文件传输方式:
发送multipart请求需使用BodyInserters.fromMultipartData()构建请求体,示例代码如下:
File file = downloadFile(key); // 直接用FileSystemResource包装File,无需转成MockMultipartFile MultiValueMap<String, Object> multipartData = new LinkedMultiValueMap<>(); multipartData.add("file", new FileSystemResource(file)); JsonNode response = Objects.requireNonNull(webClient.post() .uri(uriBuilder -> uriBuilder.path("/api/{groupId}/images") .queryParam("referenceId", referenceId) .build(1000)) .header(HttpHeaders.AUTHORIZATION, "Bearer " + auth2Service.getAccessToken()) .body(BodyInserters.fromMultipartData(multipartData)) .retrieve() .bodyToMono(JsonNode.class) .block());
若一定要使用MultipartFile,可按以下方式处理:
// 指定文件实际的Content-Type,比如图片用image/jpeg,PDF用application/pdf MultipartFile multipartFile = new MockMultipartFile(file.getName(), file.getName(), "application/octet-stream", new FileInputStream(file)); MultiValueMap<String, Object> multipartData = new LinkedMultiValueMap<>(); multipartData.add("file", multipartFile); // 后续WebClient调用同样使用BodyInserters.fromMultipartData(multipartData)
额外注意:
MockMultipartFile主要用于测试场景,生产环境优先用FileSystemResource包装File,更简洁高效;- 不要将
multipart/form-data作为单个文件的Content-Type,应使用文件对应的实际类型,或通用的application/octet-stream。
内容的提问来源于stack exchange,提问作者Chandra Shekar Bairi

