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

如何配置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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.07 14:12:02