Ktor Server在Postman中返回406错误的技术求助
我正在开发Android笔记应用的后端服务,测试/v1/users/register路由的POST请求时遇到问题:调用http://127.0.0.1:8080/v1/users/register接口,Postman返回406错误,数据库无新增数据(已通过Ktor创建数据表)。
相关代码与日志
路由代码
fun Route.userRoutes(db: repo, jwtService: JwtService, hashFunction: (String) -> String) { route("/v1/users") { post("/register") { try { val registerRequest = call.receive<RegisterRequest>() // Handle registration logic val user = User(registerRequest.email, hashFunction(registerRequest.password), registerRequest.name) db.addUser(user) call.respond(HttpStatusCode.OK, SimpleResponse(true, jwtService.generateToken(user))) } catch (e: Exception) { // Handle registration errors call.respond(HttpStatusCode.BadRequest, SimpleResponse(false, "Missing Some Fields or Registration Failed")) } } } }
RegisterRequest类
data class RegisterRequest( val email: String, val name: String, val password: String )
SimpleResponse类
package com.example.data.model data class SimpleResponse( val success: Boolean, val message: String )
控制台日志
2023-12-29 21:42:28.514 [eventLoopGroupProxy-4-1] TRACE io.ktor.server.routing.Routing - Trace for [v1, users, register] /, segment:0 -> SUCCESS @ / /session, segment:0 -> FAILURE "Selector didn't match" @ /session /json, segment:0 -> FAILURE "Selector didn't match" @ /json /, segment:0 -> SUCCESS @ / /(method:GET), segment:0 -> FAILURE "Selector didn't match" @ /(method:GET) /v1, segment:1 -> SUCCESS @ /v1 /v1/users, segment:2 -> SUCCESS @ /v1/users /v1/users/register, segment:3 -> SUCCESS @ /v1/users/register /v1/users/register/(method:POST), segment:3 -> SUCCESS @ /v1/users/register/(method:POST) /v1/users/login, segment:2 -> FAILURE "Selector didn't match" @ /v1/users/login Matched routes: "" -> "v1" -> "users" -> "register" -> "(method:POST)" Route resolve result: SUCCESS @ /v1/users/register/(method:POST) 2023-12-30 21:04:26.349 [eventLoopGroupProxy-4-1] TRACE i.k.server.engine.DefaultTransform - No Default Transformations found for class io.ktor.utils.io.ByteBufferChannel and expected type TypeInfo(type=class com.example.data.model.RegisterRequest, reifiedType=class com.example.data.model.RegisterRequest, kotlinType=com.example.data.model.RegisterRequest) for call /v1/users/register 2023-12-30 21:04:26.375 [eventLoopGroupProxy-4-1] TRACE i.k.s.p.c.ContentNegotiation - No suitable content converter found for request type class com.example.data.model.RegisterRequest 2023-12-30 21:04:26.384 [eventLoopGroupProxy-4-1] TRACE io.ktor.server.sessions.Sessions - Sending session data for /v1/users/register: MY_SESSION 2023-12-30 21:04:26.407 [eventLoopGroupProxy-4-1] TRACE i.k.s.p.c.ContentNegotiation - No suitable content converter found for response type class com.example.data.model.SimpleResponse and body SimpleResponse(success=false, message=Missing Some Fields)
Postman请求体
{ "name": "john", "email": "abcd@gmail.com", "password": "pass" }
序列化配置代码
fun Application.configureSerialization() { install(ContentNegotiation) { Json { prettyPrint = true isLenient = true encodeDefaults = false } } routing { get("/json/gson") { call.respond(mapOf("hello" to "world")) } } }
已确认信息
- Postman请求头包含
Content-Type: application/json和Accept: */* - Gradle使用最新版本依赖
问题分析与解决方案
从日志里的No suitable content converter found for request type class com.example.data.model.RegisterRequest可以明确,问题出在Ktor的ContentNegotiation插件没有正确配置序列化转换器,导致无法将请求的JSON数据反序列化为RegisterRequest对象,也无法将SimpleResponse序列化为JSON响应。
具体修复步骤:
添加序列化依赖:
如果使用Kotlinx Serialization,确保Gradle中添加以下依赖(替换$ktor_version为你使用的Ktor版本):implementation("io.ktor:ktor-serialization-kotlinx-json-jvm:$ktor_version") implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.0")修正ContentNegotiation配置:
明确指定使用Kotlinx Json转换器,修改configureSerialization函数:import io.ktor.serialization.kotlinx.json.* import kotlinx.serialization.json.Json fun Application.configureSerialization() { install(ContentNegotiation) { json(Json { prettyPrint = true isLenient = true encodeDefaults = false ignoreUnknownKeys = true // 可选,忽略请求中多余字段 }) } routing { get("/json/gson") { call.respond(mapOf("hello" to "world")) } } }为数据类添加序列化注解:
给RegisterRequest和SimpleResponse添加@Serializable注解,Kotlinx Serialization需要该注解生成序列化代码:import kotlinx.serialization.Serializable @Serializable data class RegisterRequest( val email: String, val name: String, val password: String )package com.example.data.model import kotlinx.serialization.Serializable @Serializable data class SimpleResponse( val success: Boolean, val message: String )确认Application调用序列化配置:
检查主Application类是否调用了configureSerialization(),示例:fun main(args: Array<String>): Unit = io.ktor.server.netty.EngineMain.main(args) fun Application.module() { configureSerialization() // 其他配置:configureRouting、configureDatabase等 }
完成以上步骤后重启服务,再次测试注册接口,即可正常完成JSON序列化/反序列化,406错误会消失,数据库也会新增用户数据。
内容的提问来源于stack exchange,提问作者Mr Sir

