Spring WebFlux下载图片并持久化至关系型数据库的正确方法
问题原因
你的代码返回空字节数组的核心原因是响应式操作的异步特性:调用subscribe()后,代码会立刻继续执行到return outputStream.toByteArray(),此时图片的下载和写入操作还没开始或完成,自然返回空数组。另外,DataBuffer的释放逻辑本身没问题,但异步执行导致流程没有等待IO完成。
解决方案
因为要求返回阻塞式的ByteArray,需要将响应式的WebFlux操作转为同步阻塞执行,同时确保所有数据写入完成后再返回结果。可以通过block()方法等待整个写入流程结束,同时正确处理DataBuffer的释放:
fun downloadImage(url: String): ByteArray? { val outputStream = ByteArrayOutputStream() return runCatching { // 发起请求获取DataBuffer流 val dataBufferFlux = webClient.get().uri(url) .accept(MediaType.APPLICATION_OCTET_STREAM) .retrieve() .bodyToFlux(DataBuffer::class.java) // 将DataBuffer写入输出流,并等待所有操作完成 DataBufferUtils.write(dataBufferFlux, outputStream) .doOnNext { DataBufferUtils.release(it) } // 释放已写入的DataBuffer .then() // 转换为Mono<Void>,表示整个流处理完成 .block() // 阻塞等待所有写入操作结束 // 返回结果,空数组时返回null outputStream.toByteArray().takeIf { it.isNotEmpty() } }.getOrNull() // 捕获异常并返回null,可根据需求调整异常处理逻辑 }
关键说明
- 阻塞等待:使用
then().block()确保整个DataBuffer流的写入操作全部完成后,才去读取输出流的内容。 - DataBuffer释放:通过
doOnNext { DataBufferUtils.release(it) }在每个DataBuffer写入完成后立即释放,避免内存泄漏;也可以替换为subscribe(DataBufferUtils.releaseConsumer()),但结合block()的话,用doOnNext更贴合同步阻塞的流程。 - 异常处理:用
runCatching包裹整个流程,避免网络请求或IO操作抛出未捕获异常,可根据业务需求调整异常处理逻辑(比如返回特定错误标识)。
内容的提问来源于stack exchange,提问作者Vytautas Arminas
相关产品推荐
相关产品推荐

