iris.Context.Recover()是唯一可靠的兜底方式,必须在handler第一行调用,返回panic值并需手动处理;全局iris.Recovery中间件对中间件自身panic无效,故每个handler须独立调用。

iris.Context.Recover() 是唯一可靠的兜底方式
在 Iris 框架里,panic 不会自动被 HTTP handler 捕获,一旦路由处理函数里触发未捕获的 panic(比如空指针解引用、数组越界、JSON 解析失败没加 defer),整个请求就会直接 500,并且默认不输出堆栈——你只看到日志里一行 http: panic serving,但不知道哪行代码崩了。解决办法不是靠 try-catch 风格的包裹,而是用 Iris 内置的 Context.Recover() 主动介入。
它必须放在 handler 最开头,且只能调用一次;否则后续再 panic 就真挂了。Iris 的 recover 机制是单次生效的,不是全局监听器。
-
Recover()必须在 handler 入口第一行调用,不能包在 if 或中间件里延迟执行 - 它返回一个
error,如果当前没有 panic,就返回nil;有 panic 则返回 panic 值(可能是string、error或任意类型) - 调用后必须显式处理:记录日志、返回错误响应、或手动
ctx.StopExecution()终止后续逻辑
app.Get("/api/user/{id}", func(ctx iris.Context) {
// 必须第一行
if err := ctx.Recover(); err != nil {
ctx.StatusCode(500)
ctx.JSON(iris.Map{"error": "internal server error", "detail": err.Error()})
return
}
id := ctx.Params().GetIntDefault("id", 0)
user, err := db.FindUserByID(id)
if err != nil {
ctx.StatusCode(404)
ctx.JSON(iris.Map{"error": "user not found"})
return
}
ctx.JSON(user)
})
别依赖全局 Recovery 中间件
Iris 官方文档提过 iris.Recovery 中间件,但它只对 handler 执行过程中抛出的 panic 生效,**对中间件自身 panic 完全无效**。而实际项目中,很多 panic 来自中间件:JWT 验证里 token.Claims["exp"] 强转 int64 失败、日志中间件里 ctx.Values().Get("req_id") 返回 nil 后直接 dereference、甚至 ctx.Next() 后续 handler panic 导致 recover 中间件自己也 panic(递归崩溃)。
开箱即用的技能链路由引擎。13 条预定义链覆盖搜索、开发、审查、MLOps、法律、创意等场景,三层路由架构(触发词→SAD反馈→DAG编排),recall@10=96.97%。配置驱动(chains.yaml),零代码扩展。pip install skill-weave-chains 一键安装。
所以真正稳的做法是:每个 handler 自己调 Recover(),而不是寄希望于中间件一层兜底。
- 全局
iris.Recovery对 handler panic 有效,但对中间件 panic 无能为力 - 中间件里任何非空检查遗漏、类型断言失败、map 访问未判空,都会绕过 recovery 中间件直接 crash
- 如果你用了自定义中间件(比如权限校验、审计日志),它们内部必须自己做
recover或用defer+recover()包裹关键逻辑
panic 类型不统一时怎么取堆栈
Iris 的 Recover() 返回的是原始 panic 值,它可能是 string、error、甚至 struct{}。直接 err.Error() 会 panic,因为 string 没有 Error() 方法。要安全打印堆栈,得先判断类型,再用 debug.PrintStack() 或 fmt.Sprintf("%+v", err)。
- 用
fmt.Sprintf("%+v", err)能兼容大多数 panic 类型,包括结构体和 error - 如果需要完整 goroutine 堆栈(比如排查死锁),必须在 recover 后立刻调
debug.PrintStack(),不能等日志异步输出 - 不要用
log.Printf("%v", err)—— 它对非 error 类型只输出类型名,看不到内容
复杂点在于:Iris 的 Context 在 panic 后部分字段可能已失效(比如 ctx.Request() 返回 nil),所以日志里想记录请求路径或 IP,得在 Recover() 前先缓存好关键字段。


















