【问题标题】:Spring WebFlux + Kotlin Response HandlingSpring WebFlux + Kotlin 响应处理
【发布时间】:2021-05-02 07:53:57
【问题描述】:

在将 Spring WebFlux 与 Kotlin 协程结合使用时,我很难理解所谓的简单 RESTful WS 响应处理场景。假设我们的 REST 控制器中有一个简单的 WS 方法,它应该返回可能大量(数百万)的响应“事物”:

@GetMapping
suspend fun findAllThings(): Flow<Thing> {
    //Reactive DB query, return a flow of things
}

这符合预期:只要使用流媒体类型(例如“application/x-ndjson”),结果就会流式传输到客户端。在更复杂的服务调用中,也考虑到错误/警告的可能性,我想返回以下形式的响应对象:

class Response<T> {
    val errors: Flow<String>
    val things: Flow<T>
}

这里的想法是响应要么成功(返回空错误流和事物流),要么失败(错误包含在相应的流中,而事物流为空)。在阻塞编程中,这是一个非常常见的响应习语。我现在的问题是如何使这个习语适应 Kotlin/Spring WebFlux 中的反应式方法?

我知道它可以只返回描述的响应(或 Mono 对于 Java 用户),但这有点违背了反应的目的,因为整个 Mono 在序列化时必须存在于内存中。有没有办法解决这个问题?我现在能想到的唯一可能的解决方案是自定义 Spring 编码器,它足够智能,可以流式传输错误或事物(无论存在什么)。

【问题讨论】:

    标签: spring kotlin spring-webflux kotlin-coroutines


    【解决方案1】:

    如何根据Thing 返回成功/错误?

    class Result<T> private constructor(val result: T?, val error: String?) {
    
        constructor(data: T) : this(data, null)
        constructor(error: String) : this(null, error)
        val isError = error != null
    
    }
    
    @GetMapping
    suspend fun findAllThings(): Flow<Result<Thing>> {
        //Reactive DB query, return a flow of things
    }
    

    【讨论】:

    • 嗯,这是一个有趣的方法,可以解决我的问题。作为一个(次要的)缺点,它会使响应处理更加复杂,但它确实解决了流式传输问题。我想出的另一个想法只是在服务器端抛出一个异常。我想这很适合反应式发布者的“onError()”习语。缺点是我将无法访问我可能在服务器上拥有的更多结构化错误信息 - 考虑错误对象而不是简单的字符串。
    • 我已将此答案标记为已接受 - 它似乎是最先进的最佳解决方案。进一步的调查表明,在很多情况下,反应式流媒体要么不能完全按照我的预期工作,要么根本没有提供使其值得的巨大好处。示例:流式传输复杂对象层次结构,其中根对象是轻量级的,但嵌套对象很大,无法有效地流式传输:class Thing(val name: String, val children: Flow) // 每个子对象占用 ~1MB RAM
    • 只是为了澄清一件事:反应式流(即 WebFlux 与 Spring MVC)根本不是来自服务器的流式响应,尽管这可以提供帮助。它们首先是关于非阻塞处理和资源使用优化。并非所有 API 都适合流式传输,但所有 API 都可以从响应式堆栈中受益。
    猜你喜欢
    • 2019-12-04
    • 2021-08-13
    • 1970-01-01
    • 2018-08-18
    • 1970-01-01
    • 2018-06-06
    • 2021-02-27
    • 2019-03-11
    • 2021-08-06
    相关资源
    最近更新 更多