使用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
相关产品推荐
相关产品推荐

