You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Ktor序列化ApiResponse时出现406 Not Acceptable错误的原因

为什么Ktor直接返回ApiResponse会报406 Not Acceptable,手动用Klaxon序列化却正常?

问题代码

路由代码

route("/hello") {
    get {
        println("hello there...")
        println("Hello, ${call.principal<JWTPrincipal>()?.subject}!")

        call.respond(Klaxon().toJsonString(ApiResponse(body = "Nothing found")))
//            call.respond(ApiResponse(body = "Nothing found"))

    }
}

ApiResponse定义

import kotlinx.serialization.Contextual
import kotlinx.serialization.Serializable

@Serializable
data class ApiResponse(
    val error: Boolean? = false,
    val errorMessage: String? = null,
    @Contextual
    val body: Any? = null
)

原因分析

  • 问题核心在ApiResponse的body: Any?字段:Ktor默认使用的Kotlinx Serialization序列化器,无法自动处理Any类型的序列化逻辑——哪怕加了@Contextual注解,也没有对应的序列化策略支撑。当直接调用call.respond(ApiResponse(...))时,序列化器无法生成符合请求Accept头要求的响应内容,服务器因此返回406错误(表示无法提供客户端可接受格式的响应)。
  • 而Klaxon是基于反射的JSON序列化库,它能直接识别Any字段的实际类型(这里是String)并完成序列化,生成的JSON字符串通过call.respond返回时,Ktor会将其当作纯文本/JSON响应处理,不会触发Kotlinx Serialization的序列化流程,所以能正常返回。

解决方案

  1. 改用泛型类替代Any类型(推荐方案)
    修改ApiResponse为泛型类,让序列化器明确字段类型:

    import kotlinx.serialization.Serializable
    
    @Serializable
    data class ApiResponse<T>(
        val error: Boolean? = false,
        val errorMessage: String? = null,
        val body: T? = null
    )
    

    路由中返回时指定具体类型:

    call.respond(ApiResponse(body = "Nothing found"))
    
  2. 为Any类型注册自定义序列化器
    如果必须保留Any?字段,需要为Any类型编写自定义上下文序列化器,告诉Kotlinx Serialization如何处理不同类型的Any实例,注册后即可正常使用call.respond(ApiResponse(...))。

内容的提问来源于stack exchange,提问作者Vladimir

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 03:35:16