recover必须在defer函数中直接调用才有效,仅捕获同goroutine内未处理的panic;不可用于替代error,也不能跨goroutine或捕获runtime致命错误。

recover 必须在 defer 中调用才有效
Go 没有传统 try/catch,recover 只能在 defer 函数里调用且仅对当前 goroutine 生效。如果直接写 recover() 在普通函数体中,它永远返回 nil,根本捕获不到 panic。
常见错误是把 recover 放在非 defer 位置,或者误以为它能跨 goroutine 传递异常:
func badHandler() {
recover() // ❌ 永远无效
panic("boom")
}
正确姿势是:
func goodHandler() {
defer func() {
if r := recover(); r != nil {
log.Printf("panic recovered: %v", r)
}
}()
panic("boom") // ✅ 这里触发,defer 中 recover 捕获
}
HTTP 服务中用 middleware 套一层 recover
Web 服务最常需要全局 panic 捕获,但不能每个 handler 都手写 defer —— 应该抽成中间件。注意:http.HandlerFunc 是函数类型,中间件要返回新 handler。
关键点:
-
recover()必须在 defer 内部,且 defer 要在 handler 执行前注册(即在闭包里写defer func(){...}()) - 捕获后必须显式写 response,否则连接挂起或返回空响应
- 不要忽略原始 panic 类型:
error、string、自定义 struct 行为不同,建议统一转成fmt.Sprintf("%v", r)
func RecoverMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
defer func() {
if r := recover(); r != nil {
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
log.Printf("[PANIC] %v\n%s", r, debug.Stack())
}
}()
next.ServeHTTP(w, r)
})
}
goroutine 泄漏风险:recover 不会自动清理已启动的 goroutine
很多人以为加了 recover 就“兜住”了所有问题,但 panic 发生时,如果已有子 goroutine 正在运行(比如启了 go http.Get(...)),它们不会被自动终止,可能继续跑、占内存、发请求、甚至重复写日志。
真正安全的做法是配合 context.Context 控制生命周期:
- 在 handler 入口创建带 cancel 的 context
- 所有子 goroutine 必须接收并监听该 context 的
Done() -
recover后立即调用cancel(),让下游 goroutine 主动退出
否则,你看到日志里 “panic recovered”,但后台还在悄悄跑着几个卡死的 goroutine。
recover 无法捕获 runtime 错误和 syscall 级崩溃
recover 只对 panic() 和显式调用的 panic 有效。以下情况它完全无能为力:
fatal error: all goroutines are asleep - deadlockfatal error: stack overflow- 空指针解引用(
nil pointer dereference)—— 这个其实是 panic,能捕获;但若发生在 CGO 或系统调用里,可能直接 abort - OOM 被 OS 杀掉、段错误、硬件异常
所以别指望 recover 当万能兜底。线上服务还得靠进程级监控(如 systemd restart、supervisord)、pprof 分析栈、以及静态检查(go vet、staticcheck)提前拦住空指针、channel 关闭后读写等高频 panic 场景。
真正难处理的,从来不是 panic 本身,而是 panic 发生前那些没被 cancel 掉的 context、没被 close 的 channel、没被释放的文件句柄 —— 它们不会报错,但会让服务越跑越慢。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











