在Ktor设置上下文中考虑下面的示例化:
- 一个简单的模型来解析JSON请求(旨在只接收/存储字符串):
@Serializable
data class TestingDTO(val texts: List<String>)
字符串
- Ktor入口点:
fun main() {
embeddedServer(
Netty,
port = 8080,
host = "0.0.0.0",
module = Application::myApp
).start(wait = true)
}
fun Application.myApp() {
install(ContentNegotiation) {
json()
}
routing {
post("/testing") {
runCatching {
val receivedTestingDTO = call.receive<TestingDTO>()
println(receivedTestingDTO)
call.respond(HttpStatusCode.Created)
}.onFailure {
call.respond(HttpStatusCode.BadRequest, it.message ?: "deserialization problem!!!")
}
}
}
}
型
- 对上述设置的POST请求示例:
curl -v -d '{"texts": ["foo", "bar", 1]}' -H 'Content-Type: application/json' http://127.0.0.1:8080/testing
型
- 注意:注意JSON数组同时包含字符串和数字。*
现在,如果我们运行它,基本上call.receive<TestingDTO>()
将请求的JSON“完美地”去序列化为TestingDTO
类型,即使我们在JSON数组中放入一个数字,也会导致所有项目从该数组转换为String
(为了将它们放入目标texts
列表中?)。
但是,如果我们使用其他KotlinAPI作为实现方法,例如kotlinx.serialization.json.Json
类,则示例请求会如预期的那样失败。例如,runCatching
块:
runCatching {
// now consuming request to read raw json as "text"
// and using kotlinx class to deserialize that text fails
// if in request exists a diferent type that doesn't fits the target
// TestingDTO List
val receivedTestingDTO = Json.decodeFromString<TestingDTO>(call.receiveText())
receivedTestingDTO.texts.forEach {
println("the value [$it] is instance of ${it::class}")
}
call.respond(HttpStatusCode.Created)
}.onFailure {
call.respond(HttpStatusCode.BadRequest, it.message ?: "deserialization problem!!!")
}
}
型
那么,这里到底发生了什么?为什么会有这两种不同的行为?我是否错过了关于call.receive<>()
函数规范的一些东西?
如果没有,“工作”方法值得使用吗?
1条答案
按热度按时间ldxq2e6h1#
此行为是isLenient json配置构建器的结果。
在Ktor中,在安装
ContentNegotiation
时用于所有请求的默认JSON配置是:字符串
在您的示例中,您使用了
Json.decodeFromString
而没有配置。默认情况下,isLenient
为false。你应该这样做
型
和Ktor有同样的行为
注意事项:
你可以通过在json函数中提供你自己的构建器来强制一个json配置。
型