保护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中,是通过使用该中间件来捕获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的函数。
标签:框架,GET,func,test,gin,recover,panic From: https://www.cnblogs.com/beatle-go/p/17913805.html