Go Web 应用需通过中间件+defer-recover捕获handler panic,记录带request_id的结构化日志,返回统一错误响应(code/message/request_id/timestamp),并结合超时、限流、熔断提升稳定性。

在 Go Web 应用中,异常捕获不能依赖传统 try-catch(Go 本身没有),而是要通过 HTTP 中间件 + panic 恢复 + 日志记录 + 统一错误响应 的组合方式来保障服务稳定性。关键不是“不 panic”,而是“panic 后不崩溃、可追踪、可降级”。
使用 defer-recover 拦截 handler 中的 panic
HTTP handler 是 panic 的高发区(如空指针解引用、JSON 解析失败、数据库连接突然中断)。必须在每个请求生命周期内主动恢复:
- 不要在 handler 内部写裸 panic;所有业务逻辑应返回 error,仅在不可恢复时由中间件统一处理
- 编写 recover 中间件,在 handler 执行前后用 defer+recover 捕获 panic
- 恢复后记录完整堆栈(用 debug.Stack())、标记请求 ID、返回 500 响应,避免连接挂起
封装统一错误响应结构
用户不应看到 panic 信息或内部堆栈。定义标准错误响应体,便于前端识别和监控系统聚合:
- 包含 code(如 "INTERNAL_ERROR")、message(面向用户/运维的简明提示)、request_id(用于日志关联)、timestamp
- 开发环境可额外返回 debug_info 字段(含 stack trace),生产环境默认关闭
- 所有 handler 返回 error 时,由中间件转为该结构并设对应 HTTP 状态码(如 400、401、500)
集成结构化日志与告警链路
捕获到 panic 或关键 error 后,日志必须带上下文,否则无法定位问题:
立即学习“go语言免费学习笔记(深入)”;
- 每条日志至少包含:request_id、method、path、status_code、error_type、stack_trace(生产环境可哈希脱敏)
- 使用 zap 或 zerolog 等结构化日志库,避免字符串拼接
- 对高频 panic(如 1 分钟超 5 次)触发告警(接入 Prometheus + Alertmanager 或企业微信/钉钉机器人)
补充稳定性防护:超时、限流、熔断
异常捕获是兜底,不是替代健壮性设计:
- HTTP server 设置 ReadTimeout / WriteTimeout / IdleTimeout,防慢连接拖垮服务
- 对外部依赖(DB、RPC、HTTP 调用)强制设置 context.WithTimeout,并检查 ctx.Err()
- 使用 go-hystrix 或 circuitbreaker 等库为不稳定下游添加熔断,避免雪崩
- 关键接口加轻量限流(如 token bucket),防止突发流量打穿 panic 恢复能力
不复杂但容易忽略:recover 只对当前 goroutine 有效,goroutine 泄漏或子 goroutine panic 仍会导致失控。务必确保所有 goroutine 启动处都包裹 recover,或统一用 worker pool 管理。










