首页 > 解决方案 > 尝试响应通过 StateFlow 传递的 ApplicationCall 对象后收到 ResponseAlreadySentException

问题描述

我正在 KTOR 中测试一个事件驱动的架构。我的核心逻辑保存在一个类中,该类对 StateFlow 发出的不同事件类型作出反应。EventGenerators 将事件推送到由 Core 拾取的 StateFlow 中。

但是,当核心尝试响应ApplicationCall嵌入在我的一个事件中的事件时,我会收到一个ResponseAlreadySentException,但我不确定为什么会这样。如果我绕过 StateFlow 并直接从 EventGenerator 调用 Core 类,则不会发生这种情况。我在代码中的其他任何地方都没有响应 ApplicationCalls,并且已经用断点检查了唯一的.respond行没有被多次命中。

MyStateFlow 类:

class MyStateFlow {
    val state: StateFlow<CoreEvent>
        get() = _state

    private val _state = MutableStateFlow<CoreEvent>(CoreEvent.NothingEvent)

    suspend fun update(event: CoreEvent) {
        _state.value = event
    }
}

我的核心课程:

class Core(
   myStateFlow: MyStateFlow,
   coroutineContext: CoroutineContext = SupervisorJob() + Dispatchers.IO
) {

   init {
       CoroutineScope(coroutineContext).launch {
           myStateFlow.state.collect {
               onEvent(it)
           }
       }
   }

   suspend fun onEvent(event: CoreEvent) {
      when(event) {
         is FooEvent {
            event.call.respond(HttpStatusCode.OK, "bar")
         }
         ...
      }
   }
}

我的 EventGenerator 之一是我的 KTOR 应用程序类中的路由:

get("/foo") {
   myStateFlow.update(CoreEvent.FooEvent(call))
}

但是,/f00在我的浏览器中点击会返回一条ResponseAlreadySentException或一条java.lang.UnsupportedOperationException带有消息:“无法再设置标题,因为响应已经完成”。当我在尝试不同的解决方案时,错误响应可以在两者之间切换,但它们似乎在说同样的事情:在我尝试调用之前,调用已经得到响应call.respond(...)

如果我改变我的路线而不是直接调用Core.onEvent(),点击/foo在我的浏览器中返回“栏”,这是预期的行为:

get("/foo") {
   core.onEvent(CoreEvent.FooEvent(call))
}

为了完整起见,我的依赖版本是:

implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.4.10"

implementation "io.ktor:ktor-server-netty:1.4.1"

提前感谢您提供的任何见解。

标签: kotlinkotlin-coroutinesktorkotlin-stateflow

解决方案


推荐阅读