大家好,我是渔夫子。
本文咱们介绍下recover在gin框架中的利用。
首先,在golang中,如果在子协程中遇到了panic,那么主协程也会被终止。如下:
package mainimport ( "github.com/gin-gonic/gin")func main() { r := gin.Default() // 在子协程中引起panic,主协程也会退出 go func() { panic("hello world") }() // Listen and Server in 0.0.0.0:8080 r.Run(":8080")}
panic被形容为不可解决的谬误。在web服务中就是服务会解体。当然,这在生产环境下是不可承受的。那么,如何可能做到产生panic时技能捕捉该panic又能让服务持续衰弱运行呢?
这就是golang中提供的recover函数了。recover函数可能捕捉Panic谬误并恢复程序的失常运行。
接下来,咱们看下recover函数在gin框架中是如何利用的。
首先,要提到的就是gin框架中的recovery中间件。在gin中,是通过应用该中间件来捕捉panic,并保障服务不down机的。 如果应用gin.Default()函数进行构建gin对象,那么默认就注册了Recovery中间件。
func Default() *Engine { debugPrintWARNINGDefault() engine := New() // 注册了Recovery中间件 engine.Use(Logger(), Recovery()) return engine}
其次,咱们来看下Recovery()中间件都做了些什么。
Recovery()函数定义如下:
func Recovery() HandlerFunc { return RecoveryWithWriter(DefaultErrorWriter)}
这里的DefaultErrorWriter是默认的输入端,即os.Stderr。即指谬误的输入到什么中央。
接下来看RecoveryWithWriter函数中的实现
// RecoveryWithWriter returns a middleware for a given writer that recovers from any panics and writes a 500 if there was one.func RecoveryWithWriter(out io.Writer, recovery ...RecoveryFunc) HandlerFunc { if len(recovery) > 0 { return CustomRecoveryWithWriter(out, recovery[0]) } return CustomRecoveryWithWriter(out, defaultHandleRecovery)}
这里有一个参数是defaultHandleRecovery,咱们看下它的实现:
func defaultHandleRecovery(c *Context, err any) { c.AbortWithStatus(http.StatusInternalServerError)}
就是写入了一个代表外部服务器谬误的状态码500,并完结了本次申请。
这里关键点是CustomRecoveryWithWriter的实现,代码很长,咱们分段来看。如下:
次要分三局部:
- 将日志输入到out中,这里是上述提到的DefaultErrorWriter,即os.Stderr。
- defer提早执行局部。
- c.Next()失常申请处理器局部。
这里须要留神的点就是:
- recover函数须要再defer中调用。因为defer是在函数返回时才调用,所以当产生panic时会导致函数返回,这样能力捕捉panic。
- 作为中间件运行,阐明每次申请的处理器都被中间件包装了,也就相当于每个申请处理器都有这个defer函数。
- 在defer函数中,如果捕捉了panic,则将panic的具体具体记录下来,能够发送到指定的输入中,即函数中指定的out参数(默认是os.Stderr),也能够指定其余的文件或Sentry等。
在gin中,正是该中间件的利用,确保了web服务的健壮性。当然,其余的web框架也有同样的机制,实现原理也是一样的。
公众号:Go学堂
特地阐明:你的关注,是我写下去的最大能源。点击下方公众号卡片,间接关注。关注送《100个go常见的谬误》pdf文档、经典go学习材料。