go中无全局异常捕获,recover仅作用于当前goroutine;http层需中间件兜底、业务错误须显式构造apperror类型、goroutine内须自建recover、日志须带traceid等上下文。

Go 里没有“全局异常捕获”这回事——recover 只能捕获当前 goroutine 的 panic,HTTP handler 里的 panic 不会自动传播到其他请求,更不会跨 goroutine 生效。所谓“全局错误管理”,其实是分层设计:HTTP 入口兜底、业务错误显式构造、goroutine 内部自保、日志与监控联动。
HTTP 请求层必须用中间件 recover
没加 Recovery 中间件的 Gin/Echo 服务,一旦 handler panic,就只返回空响应或默认 500,不打堆栈、不记录 traceID、前端收不到结构化错误。这不是配置问题,是缺失关键拦截点。
-
defer必须写在c.Next()之前,否则 panic 发生后中间件已退出,recover失效 - 别只打印
err.Error(),要调用debug.Stack()或runtime/debug.Stack()拿完整调用链 -
c.Abort()必须紧跟在错误响应之后,否则后续中间件仍可能执行(比如 JWT 验证中间件在 panic 后还会跑) - 返回给前端的错误体不能直接暴露
err.Error(),得走统一Response结构,且Code字段应映射 HTTP 状态码(如 404 →Code: 404),不是随便填个业务码
业务错误不能靠 panic,得定义可识别类型
把 fmt.Errorf("user not found") 当错误返回,前端无法区分是参数错、权限错还是 DB 连不上;用字符串匹配判断错误类型,一改提示文案就崩。真正可维护的做法是让错误本身携带语义。
使用 uber-go/dig 在 Golang 中实现依赖注入——基于反射容器,提供 Provide/Invoke、dig.In/dig.Out 参数与结果对象,支持命名依赖等
- 定义
type AppError struct { Code int; Message string; Err error },实现Error()方法 - 用
fmt.Errorf("xxx: %w", err)包装底层 error,保留原始调用链,后续可用errors.Is(err, ErrNotFound)判断 - 中间件里检查
err是否为*AppError类型,再决定返回什么 HTTP 状态码和 JSON 结构,而不是靠字符串包含 “not found” - 初始化失败(如 config 加载失败)可以
panic,但运行时业务错误(如用户余额不足)必须走error返回,不能panic
goroutine 里的 panic 必须自己 recover
HTTP handler 启了个 goroutine 去发 MQ 消息,里面 panic 了?主请求完全感知不到,MQ 消息丢了,日志里连影子都没有。Go 不会帮你跨 goroutine 捕获。
- 每个独立 goroutine 入口都得包一层
defer func() { if r := recover(); r != nil { ... } }() - 别只 log,要把 error 通过
chan error或errgroup.Group传回主流程统一处理 - 用
errgroup时注意:eg.Wait()返回第一个非 nil error,但所有 goroutine 的 panic 都得各自 recover,否则整个程序可能崩溃 - 后台任务(如定时同步)建议用
go func() { defer recover() }()包裹,但 recovery 后要主动上报(如发告警、写 DB 记录),不能静默吞掉
错误日志必须带上下文,不能只记 error 字符串
日志里只看到 "failed to create order",不知道是哪个用户、哪个订单号、哪台机器、traceID 是多少,查问题得翻十几份日志拼凑。错误日志不是记录发生了什么,而是帮人 5 分钟内定位根因。
- 所有
log.Printf或 zap 日志都要注入traceID、userID、reqID等字段,别依赖全局变量,用context.WithValue透传 -
panic日志必须含debug.Stack(),业务 error 日志至少含errors.Unwrap(err)层层展开的原始错误 - 敏感信息(密码、token、银行卡号)必须在日志前过滤,不能靠“开发环境不打”这种侥幸逻辑
- 错误上报到监控系统(如 Prometheus + Grafana)时,按
AppError.Code聚合,比按错误字符串聚合稳定得多
最难的部分从来不是写一个 recover 函数,而是让每个业务函数都返回可分类、可追溯、带上下文的 error,并且确保每条错误路径都被中间件、goroutine 封装、日志系统三方同时覆盖——漏掉任何一环,错误就变成黑洞。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










