@Resource("/articles/{version}")
data class Articles(val version: @Contextual ApiVersion)
fun main() {
embeddedServer(CIO, port = 8080) {
// plugins
install(Resources) {
serializersModule = SerializersModule { contextual(ApiVersion::class, ApiVersionSerializer) }
}
install(ContentNegotiation) { json() }
install(StatusPages) {
exception<InvalidApiVersion> { call, cause ->
call.respond(HttpStatusCode.NotFound, cause.message)
}
}
// Routes
routing {
get<Articles> { article ->
call.respondText("articles version ${article.version}")
}
}
}.start(true)
}
字符串
我有一个路由/article/${version}
,版本类型为enum class ApiVersion
,为此我有一个自定义序列化器。
internal data class InvalidApiVersion(override val message: String) : Exception(message)
enum class ApiVersion(val version: String) {
VERSION_1_0("v1.0"),
VERSION_1_1("v1.1"),
VERSION_1_2("v1.2"),
VERSION_1_3("v1.3");
companion object {
fun fromString(versionString: String): ApiVersion =
try { entries.associateBy(ApiVersion::version).getValue(versionString) }
catch (e: Exception) { throw InvalidApiVersion("Invalid path: $versionString - is not a valid or supported api version.") }
}
}
object ApiVersionSerializer : KSerializer<ApiVersion> {
override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("ApiVersion", PrimitiveKind.STRING)
override fun deserialize(decoder: Decoder): ApiVersion =
ApiVersion.fromString(decoder.decodeString())
override fun serialize(encoder: Encoder, value: ApiVersion) {
encoder.encodeString(value.version)
}
}
型
现在,当我尝试使用无效版本访问路由时(例如:articles/v1.88
)我从ktor获取BadRequestException
而不是自定义异常InvalidApiVersion
。
为什么会这样?**
由于一些REST规范,我需要返回一个无效的API版本404 NotFound
而不是400 BadRequest
,实现这一点的一种方法是在StatusPages处理程序中捕获BadRequestException
并返回404,但问题是我不想将所有BadRequest转换为404。
在这种情况下,如果我得到InvalidApiVersion
而不是BadRequestException
,那就太好了。有没有办法做到这一点?
更新:
@aleksei-tirman answer解决了上面代码中的问题,但在某些情况下,自定义异常可能会更深入,我的意思是,你可能需要执行cause?.cause?.cause?.cause
来获取实际的根异常。我可能是错的,但下面的功能工作!
install(StatusPages) {
exception<BadRequestException> { call, cause ->
val root = getRootCause(cause)
if (root is InvalidApiVersion) {
call.respond(HttpStatusCode.NotFound, root.message)
} else {
throw cause
}
}
}
fun getRootCause(exception: Throwable): Throwable {
var rootCause: Throwable = exception
for (depth in 1 until 50) { rootCause.cause?.let { rootCause = it } ?: break }
return rootCause
}
型
1条答案
按热度按时间66bbxpm51#
由于
BadRequestException
的原因是InvalidApiVersion
,您可以在StatusPages
插件的异常处理程序中检查:字符串