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

如何用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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.28 04:24:03