Spring WebFlux Webclient 接收应用程序/八位字节流文件作为 Mono
Posted
技术标签:
【中文标题】Spring WebFlux Webclient 接收应用程序/八位字节流文件作为 Mono【英文标题】:Spring WebFlux Webclient receiving an application/octet-stream file as a Mono 【发布时间】:2018-09-26 17:43:18 【问题描述】:我正在 Kotlin 中制作一个小型 Spring WebFlux 应用程序的原型。此应用程序需要从远程 REST 端点获取 tar 存档并将其本地存储在磁盘上。听起来很简单。
我首先创建了一个集成测试,它启动了 spring 服务器和另一个 WebFlux 服务器,并带有一个为 tar 存档提供服务的模拟 REST 端点。
测试应该是这样的:
1) 应用程序:GET mock-server/archive
2) 模拟服务器:状态为 200 的响应和正文中的 tar 存档作为附件类型
3) 应用程序:阻塞直到收到所有字节,然后解压缩并使用文件
我遇到的问题是,当我尝试将字节收集到应用程序上的 ByteArray
中时,它会永远阻塞。
我的mock-server/archive
路由到以下函数:
fun serveArchive(request: ServerRequest): Mono<ServerResponse>
val tarFile = FileSystemResource(ARCHIVE_PATH)
assert(tarFile.exists() && tarFile.isFile && tarFile.contentLength() != 0L)
return ServerResponse
.ok()
.contentType(MediaType.APPLICATION_OCTET_STREAM)
.contentLength(tarFile.contentLength())
.header("Content-Disposition", "attachment; filename=\"$ARCHIVE_FNAME\"")
.body(fromResource(tarFile))
然后我的应用使用以下命令调用它:
private fun retrieveArchive
client.get().uri(ARCHIVE_URL).accept(MediaType.APPLICATION_OCTET_STREAM)
.exchange()
.flatMap response ->
storeArchive(response.bodyToMono())
.subscribe()
private fun storeArchive(archive: Mono<ByteArrayResource>): Mono<Void>
val archiveContentBytes = archive.block() // <- this blocks forever
val archiveContents = TarArchiveInputStream(archiveContentBytes.inputStream)
// read archive
我见过How to best get a byte array from a ClientResponse from Spring WebClient?,这就是我尝试使用ByteArrayResource
的原因。
当我逐步检查所有内容时,我看到serveArchive
似乎正在工作(断言语句说我正在传递的文件存在并且其中有一些字节)。在retrieveArchive
我得到一个 200 并且可以在.headers
中看到所有适当的信息(内容类型,内容长度都看起来不错)。当我到达 storeArchive
并尝试使用 block
从 Mono 中检索字节时,它只会永远阻塞。
我完全不知道如何调试这样的东西。
【问题讨论】:
【参考方案1】:您只需从flatMap
返回转换后的正文,使其从Mono<T>
转换为T
:
client.get().uri(ARCHIVE_URL).accept(MediaType.APPLICATION_OCTET_STREAM)
.exchange()
.flatMap response ->
response.bodyToMono(ByteArrayResource::class.java)
.map archiveContentBytes ->
archiveContentBytes.inputStream
.doOnSuccess inputStream ->
//here is you code to do anything with the inputStream
val archiveContents = TarArchiveInputStream(inputStream)
.subscribe()
【讨论】:
成功了!谢谢!我最终使用了...flatMap response -> response.bodyToMono<ByteArrayResource>() .map storeArchive(it)
,只需将我的storeArchive
签名更改为ByteArrayResource
。但现在我实际上正在获取我的字节并能够解压缩存档等。非常感谢!以上是关于Spring WebFlux Webclient 接收应用程序/八位字节流文件作为 Mono的主要内容,如果未能解决你的问题,请参考以下文章
Spring WebFlux WebClient 弹性和性能
Spring 5 webflux如何在Webclient上设置超时
在 Spring WebFlux webclient 中设置超时