使用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的序列化流程,所以能正常返回。
解决方案
改用泛型类替代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"))为Any类型注册自定义序列化器
如果必须保留Any?字段,需要为Any类型编写自定义上下文序列化器,告诉Kotlinx Serialization如何处理不同类型的Any实例,注册后即可正常使用call.respond(ApiResponse(...))。
内容的提问来源于stack exchange,提问作者Vladimir
相关产品推荐
相关产品推荐

