go中无真正全局异常捕获,recover仅限当前goroutine;需分层兜底:http中间件recover、goroutine自包defer+recover、业务错误显式返回error。

Go 里没有真正意义上的“全局异常捕获”——recover 只能捕获当前 goroutine 的 panic,对 error 值完全无效,也不能跨 goroutine 生效。 所谓“全局”,其实是分层兜底:HTTP 入口用中间件、goroutine 自己加 defer、业务错误走显式 error 返回,三者缺一不可。
HTTP handler 必须用中间件 recover,且 defer 要写在 c.Next() 前
没加 Recovery 中间件的 Gin/Echo 服务,一旦 handler panic,只会返回空响应或默认 500,不打堆栈、不带 traceID、前端收不到结构化错误体。
-
defer必须出现在c.Next()之前,否则 panic 发生时中间件已退出,recover()永远拿不到值 - 别只调
c.JSON(500, ...)+c.Abort(),要用c.AbortWithStatusJSON(500, ...),避免后续中间件(如 JWT 验证)继续执行 - 日志里必须补全
debug.Stack()或runtime/debug.Stack(),不能只打err.Error() - 返回给前端的错误体必须走统一结构(如
{ "code": 500, "msg": "...", "data": null }),code字段应直接映射 HTTP 状态码
每个 goroutine 都得自己包 defer+recover,不能靠外层函数兜底
HTTP handler 里起一个 go func() { panic("x") }(),主流程完全感知不到;MQ 发送失败、定时任务 panic、后台 worker 崩溃,都会静默丢失。
诊断并恢复通过 SSH 隧道连接的 OpenClaw 节点。用于解决配对必需错误、隧道冲突、远程端点错误以及 SSH 目标配置错误等问题。
- 每个独立 goroutine 入口必须手动加
defer func() { if r := recover(); r != nil { ... } }() - 推荐封装成工具函数,比如
goSafe(func(){ ... }),内部自动注入 recover 和日志 - 用
errgroup.Group时注意:eg.Wait()只返回第一个非 nil error,但每个子 goroutine 仍需各自 recover,否则可能 panic 导致整个进程退出 - recover 后别复用原状态(比如已 close 的 channel、越界 slice),建议立即清理资源后 return,或 panic 新错误
recover 不是 error 处理替代品,业务错误必须显式返回 error 类型
把 fmt.Errorf("user not found") 当 error 返回,前端无法区分是参数错、权限错还是 DB 连不上;靠字符串匹配判断错误类型,一改提示文案就崩。
- 定义可识别类型,如
type AppError struct { Code int; Message string; Err error },实现Error()方法 - 用
fmt.Errorf("xxx: %w", err)包装底层 error,保留调用链,后续可用errors.Is(err, ErrNotFound)判断 - 中间件里检查
err是否为*AppError,再决定返回什么 HTTP 状态码和 JSON 结构,而不是靠strings.Contains(err.Error(), "not found") - 初始化失败(如 config 加载失败)可以
panic,但运行时业务错误(如用户余额不足)必须走error返回,不能panic
最易被忽略的一点:recover 后函数立即 return,panic 后的代码不会执行,但已发生的副作用(如文件写入、DB 更新、channel 发送)无法回滚。想实现“降级逻辑”,得靠显式 error 判断 + if 分支,不是靠 recover 撑住后续流程。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










