在 Ktor 中验证请求
Validate Request in Ktor
我有一个用 Ktor 制作的 API,当请求的 som 字段失败时,它 returns 500 错误,我想检查所有请求数据和 return,在本例,422.
请求class:
@Serializable
data class LoginRequest (
val email: String,
val password: String
)
路由
route("v1/auth/login") {
post {
val loginRequest = call.receive<LoginRequest>()
//LOGIN METHOD
}
}
现在Ktor显示的错误是:
[eventLoopGroupProxy-4-1] ERROR Application - Unhandled: POST - /v1/auth/login
kotlinx.serialization.MissingFieldException: Field 'password' is required for type with serial name
确保系统不会失败并响应 BadRequest 的最佳方法是什么?
如果你想在特定的地方捕获异常,你可以使用try
/catch
:
try {
val loginRequest = call.receive<LoginRequest>()
...
} catch (e: SerializationException) {
// serialization exceptions
call.respond(HttpStatusCode.UnprocessableEntity)
} catch (t: Throwable) {
// other exceptions
call.respond(HttpStatusCode.InternalServerError)
}
如果你想要一些全局 try
/catch
,Ktor 有针对这种情况的 StatusPages 功能:它会在调用处理期间捕获所有异常。
与 try
/catch
相同,您可以捕获特定异常,例如 SerializationException
,或使用 Exception
/Throwable
来捕获任何其他异常异常。
install(StatusPages) {
exception<SerializationException> { cause ->
// serialization exceptions
call.respond(HttpStatusCode.UnprocessableEntity)
}
exception<Throwable> { cause ->
// other exceptions
call.respond(HttpStatusCode.InternalServerError)
}
}
您可以使用默认 null
值使字段可为空,在遇到未知属性时忽略错误并手动验证结果对象。这是一个例子:
import io.ktor.application.*
import io.ktor.features.*
import io.ktor.http.*
import io.ktor.request.*
import io.ktor.response.*
import io.ktor.routing.*
import io.ktor.serialization.*
import io.ktor.server.engine.*
import io.ktor.server.netty.*
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.Json
@Serializable
data class LoginRequest (
val email: String? = null,
val password: String? = null
)
suspend fun main() {
embeddedServer(Netty, port = 8080) {
install(ContentNegotiation) {
json(Json {
ignoreUnknownKeys = true
})
}
routing {
post("/") {
val request = call.receive<LoginRequest>()
if (request.email == null || request.password == null) {
call.respond(HttpStatusCode.UnprocessableEntity)
return@post
}
call.respond(HttpStatusCode.OK)
}
}
}.start()
}
post {
try {
val customer = call.receive<Customer>()
customerStorage.add(customer)
call.respondText("Customer stored correctly", status = HttpStatusCode.Created)
} catch (e: SerializationException) {
call.respondText(e.localizedMessage, status = HttpStatusCode.UnprocessableEntity)
} catch (e: Exception) {
call.respondText(e.localizedMessage, status = HttpStatusCode.InternalServerError)
}
}
我有一个用 Ktor 制作的 API,当请求的 som 字段失败时,它 returns 500 错误,我想检查所有请求数据和 return,在本例,422.
请求class:
@Serializable
data class LoginRequest (
val email: String,
val password: String
)
路由
route("v1/auth/login") {
post {
val loginRequest = call.receive<LoginRequest>()
//LOGIN METHOD
}
}
现在Ktor显示的错误是:
[eventLoopGroupProxy-4-1] ERROR Application - Unhandled: POST - /v1/auth/login
kotlinx.serialization.MissingFieldException: Field 'password' is required for type with serial name
确保系统不会失败并响应 BadRequest 的最佳方法是什么?
如果你想在特定的地方捕获异常,你可以使用try
/catch
:
try {
val loginRequest = call.receive<LoginRequest>()
...
} catch (e: SerializationException) {
// serialization exceptions
call.respond(HttpStatusCode.UnprocessableEntity)
} catch (t: Throwable) {
// other exceptions
call.respond(HttpStatusCode.InternalServerError)
}
如果你想要一些全局 try
/catch
,Ktor 有针对这种情况的 StatusPages 功能:它会在调用处理期间捕获所有异常。
与 try
/catch
相同,您可以捕获特定异常,例如 SerializationException
,或使用 Exception
/Throwable
来捕获任何其他异常异常。
install(StatusPages) {
exception<SerializationException> { cause ->
// serialization exceptions
call.respond(HttpStatusCode.UnprocessableEntity)
}
exception<Throwable> { cause ->
// other exceptions
call.respond(HttpStatusCode.InternalServerError)
}
}
您可以使用默认 null
值使字段可为空,在遇到未知属性时忽略错误并手动验证结果对象。这是一个例子:
import io.ktor.application.*
import io.ktor.features.*
import io.ktor.http.*
import io.ktor.request.*
import io.ktor.response.*
import io.ktor.routing.*
import io.ktor.serialization.*
import io.ktor.server.engine.*
import io.ktor.server.netty.*
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.Json
@Serializable
data class LoginRequest (
val email: String? = null,
val password: String? = null
)
suspend fun main() {
embeddedServer(Netty, port = 8080) {
install(ContentNegotiation) {
json(Json {
ignoreUnknownKeys = true
})
}
routing {
post("/") {
val request = call.receive<LoginRequest>()
if (request.email == null || request.password == null) {
call.respond(HttpStatusCode.UnprocessableEntity)
return@post
}
call.respond(HttpStatusCode.OK)
}
}
}.start()
}
post {
try {
val customer = call.receive<Customer>()
customerStorage.add(customer)
call.respondText("Customer stored correctly", status = HttpStatusCode.Created)
} catch (e: SerializationException) {
call.respondText(e.localizedMessage, status = HttpStatusCode.UnprocessableEntity)
} catch (e: Exception) {
call.respondText(e.localizedMessage, status = HttpStatusCode.InternalServerError)
}
}