Beego 默认开启 recoverpanic = true,它在每个请求 goroutine 入口自动插入 defer recover(),捕获 panic 后返回 500 页面,但仅打印堆栈、设状态码、写响应体,不支持 traceID、自定义日志、告警或 JSON 响应。

Beego 里没有真正的“全局异常捕获”——recover 只对当前 goroutine 生效,而每个 HTTP 请求都在独立 goroutine 中运行;你不能靠 main() 里的 defer recover 拦住请求 panic,必须在请求生命周期内显式处理。
Beego 的默认 recoverpanic 是什么?
Beego 默认开启 recoverpanic = true(通过 beego.BConfig.RecoverPanic 控制),它会在每个请求 goroutine 入口自动插入一层 defer recover(),捕获 panic 后返回 500 页面。但它只做最基础的事:打印堆栈、设状态码、写响应体,不带 traceID、不调用自定义日志、不发告警、不区分业务错误类型。
常见问题:
- 日志里看不到请求路径、method、用户 ID,无法定位哪次调用崩了
- panic 堆栈被截断,缺少中间件或 service 层调用链
- 前端收到的是纯 HTML 500 页面,API 场景下应返回 JSON 错误结构
如何替换默认 panic 处理为自定义逻辑?
Beego 不提供类似 Gin 的 gin.Recovery() 中间件注册点,但支持两种等效方式:全局 filter 或控制器内 defer。优先选 filter,避免每个 controller 重复写。
实操建议:
- 用
beego.InsertFilter("*", beego.BeforeRouter, CustomRecoverFilter)注册在路由前 - filter 函数内部必须立即
defer func() { if r := recover(); r != nil { ... } }(),且c.Next()要放在 defer 块之后 - 别直接
fmt.Println(r),改用debug.Stack()获取完整调用链 - 恢复后必须调用
c.Abort(),否则后续 filter(如 JWT 验证)仍会执行 - 响应体走统一
Response结构,不要裸写c.Ctx.WriteString
Beego 中怎么区分 panic 和业务 error?
Beego 的 this.Abort("404") 或 this.Abort("dbError") 不是 panic,而是流程中断指令,由框架内部的 error handler 映射到模板或函数。它和 recover() 完全无关,也不能被 recover 捕获。
真正要分清的是:
-
panic:仅用于不可恢复场景(如 config 解析失败、DB 连接池初始化失败),发生时必须recover并记录严重日志 -
error返回值:所有可预期失败(参数错、权限不足、记录不存在)都该用return fmt.Errorf("xxx: %w", err)包装,并配合errors.Is(err, ErrNotFound)判断 -
this.Abort(xxx):仅用于跳转到预定义错误页面(HTML 场景),不适合 API 服务;API 应统一走c.Data["json"] = Response{...}; c.ServeJSON()
混淆三者会导致:API 返回 HTML、日志里全是 500 却查不到真实错误、监控指标失真。
goroutine 内 panic 怎么办?
Beego handler 里启了 go func() { ... }() 发 MQ 或调第三方?那个 goroutine 的 panic 完全不会触发 Beego 默认 recover,也不会被你的 filter 捕获。
必须手动兜底:
- 每个独立 goroutine 入口包一层
defer func() { if r := recover(); r != nil { log.Error("goroutine panic: %v, stack: %s", r, debug.Stack()) } }() - 若需向主流程反馈错误,用
errgroup.Group或chan error传回,别只打日志就完事 - 禁止在 goroutine 里调
os.Exit()或log.Fatal(),这会让整个进程退出
最容易被忽略的是:Beego 的 recoverpanic 只管 handler 主 goroutine,对子 goroutine、定时任务、后台 worker 完全无效——这些地方的 panic 必须各自守好自己的门。


















