OpenFeign多文件上传间歇性失败,报Incomplete output stream异常
OpenFeign跨微服务上传文件间歇性失败问题排查与解决
业务场景
- task-service生成Excel文件
- 通过OpenFeign以
multipart/form-data格式发送至system-service - system-service接收文件后上传至AWS S3
相关代码
Feign Client定义
@FeignClient( name = "system-service", url = "${feign.client.main.url.system}", configuration = FeignMultipartConfig.class ) public interface SystemServiceClient { @PostMapping( value = "/system-service/uploadFile", consumes = MediaType.MULTIPART_FORM_DATA_VALUE ) Map<String, Object> uploadFile( @RequestPart("file") Resource file, @RequestHeader MultiValueMap<String, String> headers ); }
待发送文件封装代码
ByteArrayResource resource = new ByteArrayResource(Files.readAllBytes(tempFile)) { @Override public String getFilename() { return fileName; } };
System-Service接收接口
@PostMapping("/uploadFile") public Map<String, Object> uploadFile( @RequestPart("file") MultipartFile file, @RequestHeader MultiValueMap<String, String> headers) { return awsService.uploadFile(file, headers); }
AWS S3上传逻辑
s3Client.putObject( request, RequestBody.fromInputStream( file.getInputStream(), file.getSize() ) );
问题现象
上传操作偶发失败,报错信息如下:
java.util.concurrent.ExecutionException: feign.RetryableException: Incomplete output stream executing POST http://localhost:9008/system-service/uploadFile
排查与解决方法
1. 修正ByteArrayResource的长度返回逻辑
ByteArrayResource默认的contentLength()虽能返回字节数组长度,但部分场景下Feign会重复计算导致长度异常。显式重写该方法确保长度准确:
ByteArrayResource resource = new ByteArrayResource(Files.readAllBytes(tempFile)) { @Override public String getFilename() { return fileName; } @Override public long contentLength() { return super.contentLength(); } };
2. 调整Feign超时配置
默认超时时间较短,大文件上传易触发流中断。在配置文件中延长超时时间:
feign: client: config: default: connectTimeout: 30000 readTimeout: 60000
3. 避免输入流重复读取
MultipartFile的输入流仅能读取一次,若在AWS上传前被提前读取或关闭,会导致数据不完整。改用字节数组方式上传:
byte[] fileBytes = file.getBytes(); s3Client.putObject( request, RequestBody.fromBytes(fileBytes) );
4. 确认Feign Multipart编码器配置
确保FeignMultipartConfig正确配置了表单编码器,避免Multipart请求编码异常:
@Configuration public class FeignMultipartConfig { @Bean public Encoder feignEncoder() { return new SpringFormEncoder(new SpringEncoder(() -> new HttpMessageConverters(new MappingJackson2HttpMessageConverter()))); } }
内容的提问来源于stack exchange,提问作者Sandip Gadade
相关产品推荐
相关产品推荐

