如何配置Ktor全局异常处理器 捕获所有已处理及未处理异常
Ktor全局异常捕获配置方案
Ktor内部的请求处理链路有默认的异常捕获逻辑,因此JVM层面的UncaughtExceptionHandler无法捕获到路由、Ktor自身处理流程中抛出的异常,需要配合官方的StatusPages插件实现全场景异常覆盖。
1. 配置StatusPages插件捕获Web请求链路所有异常
StatusPages是Ktor官方提供的异常/状态码处理插件,可以覆盖所有和Web请求相关的异常场景,包括路由逻辑抛出的异常、Ktor自身序列化/反序列化、权限校验等流程抛出的异常,以及4xx/5xx等默认状态码对应的错误场景。
import io.ktor.server.plugins.statuspages.* import io.ktor.server.application.* import io.ktor.http.* import io.ktor.server.response.* fun Application.configureGlobalExceptionHandler() { // 优先安装StatusPages插件,确保可以捕获后续其他插件抛出的异常 install(StatusPages) { // 捕获所有Throwable类型的异常,覆盖所有请求链路的已处理、未处理异常 exception<Throwable> { call, cause -> // 执行异常上报逻辑,上报到你的通知系统 reportToNotifySystem(cause, call.request) // 可选配置:自定义返回给客户端的错误响应,不配置则继续走Ktor默认响应逻辑 call.respondText( text = "服务器内部错误", status = HttpStatusCode.InternalServerError ) } // 可选配置:单独捕获特定类型的业务异常,优先级高于全局Throwable捕获 exception<BusinessException> { call, cause -> reportBusinessException(cause) call.respondText( text = cause.message ?: "业务请求错误", status = HttpStatusCode.BadRequest ) } // 可选配置:捕获Ktor默认生成的状态码错误,比如404、401等非异常类错误场景 status(HttpStatusCode.NotFound, HttpStatusCode.Unauthorized) { call, status -> reportStatusError(status, call.request.uri) call.respondText( text = when(status) { HttpStatusCode.NotFound -> "请求资源不存在" HttpStatusCode.Unauthorized -> "权限不足" else -> "请求错误" }, status = status ) } } // 后续再安装其他插件、配置路由 install(ContentNegotiation) { // 序列化配置 } routing { // 路由配置 } }
2. 配置JVM UncaughtExceptionHandler捕获非请求链路异常
StatusPages只能覆盖和Web请求相关的链路异常,自定义后台线程、定时任务等非请求场景抛出的异常,仍需要配置全局未捕获异常处理器捕获:
fun main() { // 配置全局线程未捕获异常处理器 Thread.setDefaultUncaughtExceptionHandler { thread, throwable -> // 上报非请求链路的未捕获异常 reportToNotifySystem(throwable) println("线程${thread.name}抛出未捕获异常: ${throwable.message}") } // 启动Ktor服务 embeddedServer(Netty, port = 8080, module = Application::configureGlobalExceptionHandler).start(wait = true) }
3. 协程全局异常捕获补充
如果项目中使用了全局作用域启动的独立协程任务,还需要配置CoroutineExceptionHandler捕获协程内未处理的异常:
// 全局协程异常处理器 val globalCoroutineExceptionHandler = CoroutineExceptionHandler { _, throwable -> reportToNotifySystem(throwable) println("全局协程抛出未捕获异常: ${throwable.message}") } // 使用示例:启动全局协程时传入处理器 GlobalScope.launch(globalCoroutineExceptionHandler) { // 后台异步任务逻辑 }
注意事项
- StatusPages插件需要优先于Routing、ContentNegotiation等其他插件安装,才能完整捕获其他插件运行时抛出的异常
- 业务代码中主动捕获且未重新抛出的异常不会触发全局处理器,需在catch块中手动调用上报逻辑
- 配置
exception<Throwable>后不会影响Ktor的正常错误响应流程,你可以选择在回调中自定义响应,也可以直接抛给后续逻辑处理
内容的提问来源于stack exchange,提问作者Infinity_dev
相关产品推荐
相关产品推荐

