Iris 默认不自动 recover 中间件 panic,需显式注册 iris.Recover(且置于所有中间件之前);panic 未被捕获会导致 goroutine 崩溃、连接断开、无堆栈日志;应使用 iris.RecoverWithFunc 统一转为 JSON 响应,并调用 ctx.StopExecution() 防止后续执行。

中间件里 panic 了,为什么没被 recover?
Iris 默认不自动 recover 中间件里的 panic,这和 Gin 的 Recovery() 中间件不同。一旦中间件 panic,整个 goroutine 崩溃,HTTP 连接直接断开,日志里可能只看到 panic: runtime error,没有堆栈或上下文信息。
常见错误现象:JWT 解析失败时直接 panic("invalid token"),结果服务偶发 502 或连接重置,而不是返回 401。
- 必须显式注册
iris.Recover中间件,且要放在所有自定义中间件之前(app.Use(iris.Recover)) -
iris.Recover只捕获当前中间件链的 panic,如果在go func()里 panic,它无能为力 - 别依赖
defer+recover手写恢复逻辑——Iris 的执行流是线性的,手动 recover 容易漏掉 ctx 状态清理
怎么让中间件错误统一转成 JSON 响应?
默认 iris.Recover 返回的是 HTML 错误页,对 API 场景不友好。需要自定义 recovery 行为,把 panic 或 error 映射为标准 JSON 格式。
- 用
iris.RecoverWithFunc替代原始iris.Recover,传入一个处理函数 - 函数内判断
err类型:如果是自定义错误(如*jwt.ValidationError),设状态码为 401;如果是数据库超时,设为 503 - 务必调用
ctx.StopExecution(),防止后续中间件或 handler 再执行 - 示例:
ctx.StatusCode(401); ctx.JSON(map[string]string{"error": "token expired"})
中间件里 return error 而不是 panic,怎么透传到顶层?
Iris 的中间件签名是 func(iris.Context),不支持返回 error。所以不能像 Go 标准库那样靠 if err != nil { return err } 向上抛。
- 推荐方案:用
ctx.Values().Set("error", err)存储错误,再在全局 recovery 中间件里统一读取并响应 - 注意顺序:这个
Values().Set必须发生在ctx.Next()之前,否则 recovery 中间件拿不到 - 更安全的做法是封装一个 helper 函数,比如
abortWithError(ctx, 400, "bad request"),内部完成状态码、JSON、StopExecution三步 - 避免在多个中间件里反复 set 同一个 key,建议用唯一前缀,如
"middleware.auth.error"
ctx.StopExecution() 之后还调 ctx.Next() 会怎样?
不会 panic,但行为不可控:后续中间件仍可能执行,handler 也可能被执行,导致重复写响应、数据库重复操作等副作用。
- 典型错误:鉴权中间件里写了
ctx.JSON(403, ...); ctx.StopExecution(),末尾却忘了删掉ctx.Next() - Iris 不校验是否已终止,它只是跳过剩余中间件链,但当前函数里剩下的代码照常运行
- 最稳妥的写法是把
ctx.Next()放在 if 分支外,并用 early return 控制流程,例如:if !valid { abort(); return } - 尤其注意 defer 里的 ctx 操作——
defer ctx.Next()在已 Stop 的情况下仍会触发,极易出错
ctx.Next() 写错,就可能让 401 变成 500,或者让日志中间件多记一条本不该存在的请求。


















