go http中间件需在最外层用defer+recover捕获panic,显式写入500响应;应定义apperror结构体统一错误格式,按类型设置状态码和响应体;注意recover仅对同goroutine有效,且须确保中间件真正包裹handler。

Go HTTP 中间件怎么捕获 handler panic
Go 的 http.ServeHTTP 不会自动 recover panic,一旦 handler 内部 panic,连接直接断开,还可能泄露敏感堆栈。必须手动加 recover。
- 在中间件最外层用
defer+recover()捕获 panic,否则它会向上冒泡到 net/http 默认日志逻辑 - 不要只 recover 后
log.Print就完事——得主动写响应,比如w.WriteHeader(500)和w.Write([]byte("Internal Error")) - 注意:recover 只对当前 goroutine 有效;如果 handler 里启了新 goroutine 并 panic,这个中间件捕不到
如何统一格式化 error 并透传到响应体
原生 error 接口太弱,无法携带状态码、错误码、调试信息。直接返回 err.Error() 会导致前端无法区分是参数错还是服务挂了。
- 定义结构体实现
error接口,比如type AppError struct { Code int `json:"code"` Msg string `json:"msg"` Debug string `json:"debug,omitempty"` } - 在中间件里判断
err是否为*AppError,是则取.Code设为 HTTP 状态码,.Msg返回给前端 - 开发环境可加
.Debug字段输出runtime/debug.Stack(),但生产环境必须关掉
为什么 defer recover 有时不生效
不是写了 defer 就万事大吉。常见失效场景比想象中多。
- 中间件没真正 wrap 到最终 handler:比如用了
http.HandleFunc直接注册,绕过了你写的中间件链 - panic 发生在
defer语句之后、handler 函数 return 之前——但 recover 必须在同一个函数内且在 panic 之前声明 - 用了第三方路由库(如 gin、echo),它们自带 panic recovery,你的中间件可能被跳过或执行顺序不对;查清它们的 middleware 执行时机再决定是否叠加
要不要在中间件里重试或降级
别做。HTTP 中间件不是容错编排层。
立即学习“go语言免费学习笔记(深入)”;
- 重试要分幂等性:GET 可重试,POST/PUT 重试可能造成重复下单
- 降级逻辑(比如 fallback 到缓存)应该放在业务 handler 内部,而不是中间件里——中间件不知道该降级成什么
- 真要统一兜底,也只限于返回预设的静态错误页或 JSON,别动业务状态










