recover中间件必须包裹c.next()才能捕获panic,且仅对当前goroutine生效;goroutine需独立defer+recover;panic非业务错误,应区分error处理。

recover 中间件必须包裹 c.Next() 才能生效
panic 只有发生在 c.Next() 执行期间及后续调用链中,才会被中间件里的 recover() 捕获。这不是“写了 defer 就万事大吉”,而是作用域问题。
-
defer只覆盖它所在匿名函数的作用域,不是整个 handler 函数体 - 如果把可能 panic 的代码(比如解包空指针、强制类型断言)写在
c.Next()前面,recover()完全收不到 - 漏写
c.Next()或把它放在defer外面,等于没挂载业务逻辑,中间件形同虚设 - 前置中间件(如
gin.BasicAuth)若注册在Recovery()之前,其内部 panic 也逃逸出捕获范围
goroutine 内 panic 不会被外层 recover 拦截
Go 的 recover() 只对当前 goroutine 生效。HTTP handler 启的子 goroutine 里 panic,顶层中间件完全无感——连接会静默断开,日志里连堆栈都没有。
使用 uber-go/dig 在 Golang 中实现依赖注入——基于反射容器,提供 Provide/Invoke、dig.In/dig.Out 参数与结果对象,支持命名依赖等
- 每个 goroutine 都得自己加
defer + recover() - recover 后务必调用
debug.Stack(),不能只打印err;否则只有 panic 消息,找不到哪行代码崩的 - 建议统一封装一个
safeGo()工具函数,自动包一层 recover + 日志 + 上报,避免重复写 - 别指望靠全局机制兜底——goroutine 错误必须显式处理,这是 Go 的设计约束
http.Error 和 c.AbortWithStatusJSON 的状态码行为差异
两者都会终止响应,但语义和副作用不同,混用会导致前端解析混乱或中间件执行错乱。
-
http.Error()直接写响应头和 body,不触发 Gin 的c.Abort(),后续中间件仍可能执行 -
c.AbortWithStatusJSON()内部调用c.Abort(),阻止后续所有中间件和 handler,但defer仍会运行(所以 recover 日志不会丢) - 已定义统一响应结构(如
rsp.FailMsg())时,就别穿插用http.Error(),否则前端要兼容两种格式 - 状态码必须显式设置:返回
errors.New("not found")不等于 HTTP 404,必须配c.AbortWithStatusJSON(http.StatusNotFound, ...)
panic 不等于业务错误,别滥用
用 panic("user_id is empty") 是反模式。Go 的 panic 是程序级崩溃信号,代表不可恢复的逻辑缺陷,不是校验失败的业务分支。
- 业务错误(参数非法、资源不存在)应走
return nil, errors.New(...)或自定义*AppError - 真正该 recover 的 panic 是那些你无法提前防御的底层崩溃:模板渲染时
reflect.Value.Interface()崩、第三方库内部 panic、map 写入未初始化等 - recover 后不要简单吞掉 panic——至少记录堆栈、上报监控,否则等于掩耳盗铃
- error 包装要用
%w,保留调用链;否则errors.Is(err, ErrNotFound)会失效
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










