go模块中panic不会自动捕获,必须在每个goroutine内显式用defer+recover处理,且仅对当前goroutine生效;http handler等需手动包装,否则导致静默失败或进程崩溃。

Go 模块里 panic 不会被自动捕获,必须手动 recover
Go 的 panic 在模块内部(比如工具函数、初始化逻辑、中间件)触发时,不会像 Java 那样被框架兜底。如果没在 goroutine 内部用 defer + recover() 拦住,它会一路向上冒泡直到进程退出——哪怕只是某个 HTTP 请求 handler 里 panic,也会导致整个服务实例崩溃(标准库 http.ServeHTTP 不做 recover)。
常见错误是只在顶层 main() 里 recover,但那只能拦住 main goroutine 的 panic,对 HTTP handler、goroutine 启动的子任务完全无效。
-
recover()只对当前 goroutine 生效,且必须在defer中调用 - 子 goroutine(如
go func(){}())里的 panic 必须在那个 goroutine 内部 recover,父 goroutine 无法代劳 - 别依赖日志库自动捕获 panic——log 包、zap、zerolog 都不提供该能力,它们只负责输出
业务 error 和 panic 必须严格区分,混用会导致日志和响应失控
把数据库连接失败、参数校验不通过这类可预期问题用 panic 处理,等于放弃控制权:你没法返回 400 Bad Request 或 404 Not Found,只能硬塞 500 Internal Server Error;前端收不到结构化错误码,监控也抓不到业务维度指标。
真正该用 panic 的场景极少:init() 里配置加载失败、全局单例构造失败、断言不该发生的逻辑分支(如 switch 缺少 default 且所有 case 已穷举)。
- 常规错误一律走
error返回值,由上层 handler 显式检查并设置状态码 - 用
fmt.Errorf("xxx: %w", err)包装原始错误,保留堆栈上下文(Go 1.13+) - 避免在日志里重复打印同一错误:Model 层不打日志,只返回 error;Service 层或 handler 层统一记录一次,并附加请求 ID、用户 ID 等上下文
全局错误响应格式不统一,前端解析就会出错
后端返回 {"error":"xxx"}、{"message":"xxx","code":1001}、纯文本甚至空响应,前端得写一堆 if-else 判断,稍有遗漏就静默失败或 crash。这不是前端的问题,是后端没定义契约。
建议定义统一响应结构体,所有 handler(包括错误路径)都走同一序列化逻辑:
type Response struct {
Code int `json:"code"`
Message string `json:"message"`
Data interface{} `json:"data,omitempty"`
}
- HTTP 状态码和 JSON 中的
Code字段要解耦:前者控制网络层行为(缓存、重试),后者供前端业务逻辑判断 - 敏感字段(如密码、token、内部路径)必须过滤,别直接把
err.Error()塞进响应体 - 框架如 Gin 的
c.Error()只是记录错误,不自动渲染响应;真正要返回 JSON 错误,得调用c.JSON(status, resp)
日志里没有堆栈,等于没留线索
只记 log.Printf("failed to parse config: %v", err),查问题时根本不知道是哪行代码、哪个函数、哪个 goroutine 出的问题。Go 原生 error 接口不带堆栈,必须显式注入。
推荐方案:用 github.com/pkg/errors 或 Go 1.13+ 的 fmt.Errorf("%w", err) + %+v 格式化输出:
log.Printf("PANIC in %s %s: %+v", r.Method, r.URL.Path, err)
// %+v 能展开 pkg/errors.Wrap 或 fmt.Errorf(%w) 生成的堆栈
- 别用
err.Error()打印堆栈——它只返回字符串,不包含文件行号 - 第三方日志库(如 zap)支持结构化字段,可把
runtime/debug.Stack()作为stack字段写入,但注意长度限制和性能开销 - 生产环境慎用
debug.PrintStack(),它直接输出到 stderr,可能污染日志流;优先用debug.Stack()获取字节切片再交给日志系统
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











