GO错误处理【2】os.Exit(1)/panic/返回err的应用场景

可以详细讲一讲什么时候用os.Exit(1),什么时候用panic,什么时候只是返加err?

从 Java/PHP 转到 Go,理解这三者的界限是进阶的核心。Java/PHP 习惯用 try-catch 或直接报错,而 Go 讲究"各司其职"。

1. 什么时候返回 error?

场景:99% 的业务逻辑。

在 Go 中,错误被视为正常的数据流。只要是"预料之中"的问题,都应该返回 error。

  • 例子:数据库查不到数据、用户密码错误、输入参数不合法、网络请求超时。
  • 原则:不要因为这些事让程序死掉。你应该把 err 一层层往上传,直到 Handler 层,然后调用你写的 res.ApiError 返回给前端。

2. 什么时候用 panic?

场景:真正的异常(不该发生的事)。
panic 意味着程序遇到了逻辑死胡同,无法继续执行当前的逻辑。

  • 例子:
    • 代码 Bug:比如访问了 nil 指针、数组越界。
    • 核心环境崩溃:程序运行到一半,发现某个必须存在的配置文件被删了。
  • 处理:在 Web 开发中,我们通常会在最外层用 Recovery 中间件 把 panic 拦住,转成 500 错误,防止整个进程挂掉。

3. 什么时候用 os.Exit(1)?

场景:启动即崩溃(初始化阶段)。

这是最狠的一招,直接杀掉进程,不给任何后悔的机会(连 defer 都不会执行)。

  • 例子:main 函数启动时,发现数据库连不上、端口被占用、环境变量没配置。
  • 原则:如果程序的基础设施都不健全,跑起来也是带病工作,不如直接"自杀"。它只应该出现在 main.go 或初始化的那一刻。

4. 必须补上的"保命符":Recovery 中间件

你现在"裸奔"没加 Recovery,万一某个接口的代码写了 a := nil; fmt.Println(a.Name),你的整个后端就直接没了。

建议把这个中间件加在 RequestLogger 之前:

复制代码
// middleware/recovery.go
func Recovery(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		defer func() {
			if err := recover(); err != nil {
				// 1. 记录详细的崩溃日志
				infra.Log("panic").Error("程序崩溃了", 
					"err", err, 
					"uri", r.RequestURI,
				)
				
				// 2. 给前端回个 500,别让请求一直挂着
				w.Header().Set("Content-Type", "application/json")
				w.WriteHeader(http.StatusInternalServerError)
				// 这里可以用你之前的 res.ApiError
				json.NewEncoder(w).Encode(map[string]any{
					"code": 500,
					"msg":  "服务器内部错误,请稍后再试",
				})
			}
		}()
		next.ServeHTTP(w, r)
	})
}

总结建议:

  1. 启动时:连不上 DB 这种死罪,用 os.Exit(1) 或 log.Fatal。
  2. 写业务时:遇到问题(如查不到用户),一律 return err。
  3. 万一写出 Bug:靠 Recovery 中间件兜底,把 panic 变成日志和 500。
相关推荐
猪猪拆迁队11 小时前
跨电脑复制共享-WebRTC 打洞踩坑
前端·后端·go
小小龙学IT12 小时前
Go 语言 gRPC(grpc-go)深度解析
rpc·架构·golang·go
newerp15 小时前
pprof 火焰图(Flame Graph)阅读与热点代码重构实战
后端·程序员·go
云浪1 天前
Go源码分析:搞懂 Go 是如何实现堆的
后端·go·源码阅读
montEvergreen1 天前
RTMP 里的那根“连接线”:读一份 NetConnection 源码
后端·go
montEvergreen1 天前
RTMP 握手:一场客户端与服务端的“暗号”对决
后端·go
newerp1 天前
sync.Mutex 源码深度拆解:正常模式(自旋)与饥饿模式
后端·程序员·go
montEvergreen2 天前
RTMP 王国的“信笺百科全书”
后端·go
TechLee2 天前
Go 泛型统一 API 响应设计的最佳实践
后端·架构·go
我的div丢了肿么办4 天前
go语言中管道 channel的使用
后端·go