• 「Go框架」gin框架是如何处理panic的?


    本文我们介绍下recover在gin框架中的应用。 首先,在golang中,如果在子协程中遇到了panic,那么主协程也会被终止。如下:

    package main
    
    import (
    	"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")
    }
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    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
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    其次,我们来看下Recovery()中间件都做了些什么。

    Recovery()函数定义如下:

    func Recovery() HandlerFunc {
    	return RecoveryWithWriter(DefaultErrorWriter)
    }
    
    • 1
    • 2
    • 3

    这里的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)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    这里有一个参数是defaultHandleRecovery,我们看下它的实现:

    func defaultHandleRecovery(c *Context, err any) {
    	c.AbortWithStatus(http.StatusInternalServerError)
    }
    
    • 1
    • 2
    • 3

    就是写入了一个代表内部服务器错误的状态码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框架也有同样的机制,实现原理也是一样的。

  • 相关阅读:
    C语言内存函数
    SpringBoot拉取高德天气预报数据
    ICCV2021|你以为这是一个填色模型?其实我是检索模型!
    剑指offer——JZ68 二叉搜索树的最近公共祖先 解题思路与具体代码【C++】
    【深度学习实验】线性模型(二):使用NumPy实现线性模型:梯度下降法
    停车场系统源码
    Day 62 django form modelform组件
    【RF】射频集成电路与系统设计
    毫末速度:中国自动驾驶落地最快的1000天
    2023全新云渲染测评!效果图渲染哪个平台性价比更高?
  • 原文地址:https://blog.csdn.net/m0_73728511/article/details/133325772