如何用Spring Reactive WebClient实现文件边下载边流式上传
实现方案说明
你的基础思路完全正确,核心逻辑就是通过Flux<DataBuffer>做流的中转:下载端返回的数据流是分块的DataBuffer序列,直接传递给上传端作为请求体,全程不会将全量文件加载到内存,也不会写入磁盘,完全符合你的需求。
你当前的极简写法缺少必要的配置和响应式流程收尾,完整的可运行实现如下:
import org.springframework.core.io.buffer.DataBuffer import org.springframework.http.MediaType import org.springframework.web.reactive.function.client.WebClient import org.springframework.web.reactive.function.client.body import reactor.core.publisher.Mono // 全局复用WebClient实例(线程安全,无需每次调用新建) private val downloadWebClient = WebClient.builder() .codecs { configurer -> // 调整单块数据最大内存限制,默认256KB,按需调整避免大分块报错 configurer.defaultCodecs().maxInMemorySize(16 * 1024 * 1024) } .build() private val uploadWebClient = WebClient.builder().build() fun streamTransfer(downloadUrl: String, uploadUrl: String): Mono<Void> { // 拿到下载端的流式DataBuffer序列 val dataBufferFlux = downloadWebClient.get() .uri(downloadUrl) .retrieve() .bodyToFlux(DataBuffer::class.java) // 直接将流传递给上传端作为请求体 return uploadWebClient.post() .uri(uploadUrl) // 按需设置Content-Type,不确定文件类型可以用通用二进制流类型 .contentType(MediaType.APPLICATION_OCTET_STREAM) .body(dataBufferFlux) .retrieve() // 等待上传完成返回结果 .bodyToMono(Void::class.java) }
注意事项
WebClient本身是线程安全的,全局复用即可,重复调用create()方法会反复创建连接池,严重降低传输性能。- 框架会自动使用
Transfer-Encoding: chunked方式完成流式上传,不需要提前知道文件总大小;如果上传目标要求必须携带Content-Length头,只需要额外从下载响应头中获取长度再设置到上传请求头即可,不需要修改流传输逻辑。 - 不需要手动处理DataBuffer的内存释放,Spring WebClient会在上传流程结束(成功/失败)后自动回收资源,不会出现内存泄漏。
- 可以根据业务需求在对应的Flux/Mono上追加
retry()、timeout()等操作符,实现重试、超时控制等能力。
内容的提问来源于stack exchange,提问作者Vahid
相关产品推荐
相关产品推荐

