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

Ktor使用Location特性开发REST API时POST JSON参数为空如何解决

问题根因

你遇到POST请求接收的title字段为空的问题,核心通常是两点:

  • 未正确安装配置JSON序列化插件,Ktor无法将请求体的JSON数据反序列化为目标类
  • 用于Location路由定义的类,未适配序列化规则,导致反序列化时字段匹配失败

可运行完整示例

1. 所需依赖(Gradle Kotlin DSL配置)

dependencies {
    implementation("io.ktor:ktor-server-core-jvm:2.3.3")
    implementation("io.ktor:ktor-server-netty-jvm:2.3.3")
    // Location特性依赖
    implementation("io.ktor:ktor-server-locations-jvm:2.3.3")
    // JSON序列化依赖
    implementation("io.ktor:ktor-server-content-negotiation-jvm:2.3.3")
    implementation("io.ktor:ktor-serialization-kotlinx-json-jvm:2.3.3")
}

2. 完整业务代码

import io.ktor.server.application.*
import io.ktor.server.engine.*
import io.ktor.server.netty.*
import io.ktor.server.plugins.contentnegotiation.*
import io.ktor.server.plugins.locations.*
import io.ktor.server.request.*
import io.ktor.server.response.*
import io.ktor.server.routing.*
import io.ktor.server.locations.*
import kotlinx.serialization.Serializable

// 同时用于Location路由和请求体反序列化的类需要加@Serializable注解
@Serializable
@Location("/books")
data class BookRequest(val title: String = "")

// 模拟书籍处理逻辑
object BookHandler {
    private val books = mutableListOf("The Hobbit", "1984")
    fun listBooks() = books
    fun addBook(title: String) {
        books.add(title)
    }
}

fun Application.module() {
    // 安装Location插件
    install(Locations)
    // 安装JSON序列化插件
    install(ContentNegotiation) {
        json()
    }

    routing {
        get<BookRequest> {
            // 返回书籍列表JSON
            call.respond(BookHandler.listBooks())
        }

        post<BookRequest> {
            // 从请求体反序列化得到BookRequest对象
            val requestBody = call.receive<BookRequest>()
            BookHandler.addBook(requestBody.title)
            // 重定向到新书籍的资源路径,示例用书籍标题作为路径参数
            call.respondRedirect("/books/${requestBody.title}")
        }

        // 可选:单本书籍详情路由示例
        @Serializable
        @Location("/books/{title}")
        data class SingleBookRequest(val title: String)
        get<SingleBookRequest> { req ->
            call.respond("Book detail: ${req.title}")
        }
    }
}

fun main() {
    embeddedServer(Netty, port = 8080, module = Application::module).start(wait = true)
}

3. 测试验证

执行你原来的curl命令即可:

curl --header "Content-Type: application/json" \
  --request POST \
  --data '{"title":"Hitchhiker"}' \
  http://localhost:8080/books -v

你会看到返回302重定向响应,Location头为/books/Hitchhiker,再调用GET /books接口即可看到新添加的书籍已经在列表中。


注意事项

  • 用于反序列化的data class必须添加kotlinx序列化的@Serializable注解,否则Ktor无法正常解析JSON
  • 不要混淆Location的路由参数和请求体参数:如果你的Location类有路径参数(比如/books/{id}里的id),路径参数会被Location插件自动填充,call.receive得到的是请求体里的字段,两者互不影响。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 06:09:05