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

使用Spring WebClient下载文件存入S3时Content-Length传递问题

解决方案

问题核心是你把Content-Length存在Flux的上下文里,但AsyncRequestBody的contentLength()方法无法访问这个上下文——S3客户端可能在订阅Flux之前就会调用该方法获取长度,此时上下文还未生效。

调整思路:先通过WebClient获取响应头拿到Content-Length,再单独持有这个值,同时获取响应体的Flux,这样就能在AsyncRequestBody中直接使用该值。

修改后的Kotlin代码如下:

// 先获取响应,同时拿到Content-Length和响应体Flux
val responseMono = webclient
    .get()
    .uri(fileUrl)
    .exchangeToMono { response ->
        val contentLength = response.headers().contentLength()
        val byteBuffers = response.bodyToFlux<ByteBuffer>()
        Mono.just(Pair(contentLength, byteBuffers))
    }

// 基于响应数据构建S3请求
return responseMono.flatMap { (contentLength, byteBuffers) ->
    val asyncRequestBody = object : AsyncRequestBody {
        override fun subscribe(s: Subscriber<in ByteBuffer>) {
            byteBuffers.subscribe(s)
        }

        override fun contentLength(): Optional<Long> {
            return Optional.ofNullable(contentLength)
        }
    }

    s3Client.putObject(
        PutObjectRequest.builder()
            .key(fileKey)
            .bucket(s3bucket)
            .build(),
        asyncRequestBody
    ).toMono()
}

关键改动说明

  • 用exchangeToMono替代exchangeToFlux,先完整获取响应对象,一次性拿到Content-Length和响应体Flux,避免上下文传递的问题。
  • 将Content-Length作为独立变量持有,在AsyncRequestBody的contentLength()方法中直接返回该值的Optional包装。
  • 通过flatMap串联操作,确保拿到Content-Length和响应体后再构建S3请求。

内容的提问来源于stack exchange,提问作者pixel

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 23:45:06