Golang - gin框架是如何处理panic
保护gin构建的web app不panic的方式,简单来说:
1)主程中的panic本身是会被gin拦截的
2)协程中的panic需要手动使用defer和recover进行保护
情景
在用gin构建项目,运行web app并上线了之后,或许有一些请求会经过业务,在特定的情况下出发会触发golang中的panic
按照golang的设定,一旦panic,如果不在函数调用栈中存在recover,那么是一定会使得整个程序终止的
但是线上的服务是不能够因为一两个的请求就直接终止,这样非常危险,所以需要手段来阻止web app在panic的情况下直接终止
解决方案
1)主程序中的panic
对于gin这个web框架来说,主程序中的panic是会被自动recover,还会打印出非常详细的日志信息,比如
package main
import (
"fmt"
"github.com/gin-gonic/gin"
)
func main() {
r := gin.Default()
r.GET("/test", func(ctx *gin.Context) {
panic("test panic")
})
r.GET("/hello", func(ctx *gin.Context) {
fmt.Println("test hello")
})
r.Run(":857")
}
原因:在gin中,是通过使用Recovery()中间件来捕获panic,并保证服务不down机。 如果使用gin.Default()函数进行构建gin对象,那默认就注册了Recovery中间件。
func Default() *Engine {
debugPrintWARNINGDefault()
engine := New()
// 注册了Recovery中间件
engine.Use(Logger(), Recovery())
return engine
}
2)协程中的panic
不过非常可惜的是,对于协程中的panic,gin并不能做到自动recover并打印日志信息,比如
package main
import (
"fmt"
"github.com/gin-gonic/gin"
)
func main() {
r := gin.Default()
r.GET("/test", func(ctx *gin.Context) {
go func() {
panic("test panic")
}()
})
r.GET("/hello", func(ctx *gin.Context) {
fmt.Println("test hello")
})
r.Run(":857")
}
协程解决方案
recover函数能够捕获Panic错误并恢复程序的正常运行。
所以,对于协程,要手动进行defer
和recover
来避免app的退出和打印日志信息,比如上面的代码应该修改为
r.GET("/test", func(ctx *gin.Context) {
go func() {
defer func() {
if err := recover(); err != nil {
fmt.Printf("error: %v\n", err)
}
}()
panic("panic")
}()
})
可以看到app正常响应了请求,并且没有退出并打印了日志,想要更多定制操作可以修改defer的函数。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· DeepSeek 开源周回顾「GitHub 热点速览」