如何在 Spring 反应式 WebClient 中 return Kotlin 协程流

How to return a Kotlin Coroutines Flow in Spring reactive WebClient

Spring 5.2 带来了 Kotlin 协程支持,Spring 反应式 WebClient 在 Kotlin 扩展中获得了协程支持。

我已经创建了将 GET /posts 作为流程公开的后端服务,检查代码 here

@GetMapping("")
fun findAll(): Flow<Post> =
        postRepository.findAll()

在客户端示例中,我尝试使用 WebClient 通过以下方式使用此 api。

@GetMapping("")
suspend fun findAll(): Flow<Post> =
        client.get()
                .uri("/posts")
                .accept(MediaType.APPLICATION_JSON)
                .awaitExchange()
                .awaitBody()

由于 Flow 类型的 Jackson 序列化而失败。

由于上面表达式中的 awaitXXX 方法,我必须使用 suspend 修饰符才能获得乐趣。

但如果我将正文类型更改为任何,则以下内容有效,请检查 compelete codes

GetMapping("")
suspend fun findAll() =
        client.get()
                .uri("/posts")
                .accept(MediaType.APPLICATION_JSON)
                .awaitExchange()
                .awaitBody<Any>()

阅读 spring 参考文档的 the Kotlin Coroutines 后,应将 Flux 转换为 Kotlin 协程 Flow。如何处理 return 类型到 Flow 并在此处删除 suspend

Update: return类型改成Flow,这里查看最新的source codes,我觉得可能是[=46=的一部分] 5.2.0.M2。 suspend 修饰符对于 webclient api 中的 2 阶段协程操作是必需的,正如 Sébastien Deleuze 在下面解释的那样。

首先要了解的是,返回 Flow 不需要为处理程序方法本身使用挂起函数。使用 Flow,挂起函数通常隔离在 lambda 参数中。但是在这个(常见的)用例中,由于 WebClient 2 阶段 API(首先得到响应,然后得到正文)我们需要处理程序方法暂停 awaitExchange 然后将正文设为 Flow,扩展名 bodyToFlow

@GetMapping("")
suspend fun findAll() =
    client.get()
        .uri("/posts")
        .accept(MediaType.APPLICATION_JSON)
        .awaitExchange()
        .bodyToFlow<Post>()

从 Spring Framework 5.2 M2 和 Spring Boot 2.2 M3 开始支持(参见 related issue). See also my related detailed blog post