likes
comments
collection
share

探究 Go 的高级特性之 【捕获panic:Gin框架中的recover中间件】

作者站长头像
站长
· 阅读数 55

在Go语言中,当程序出现panic(即运行时错误)时,程序会立即停止当前的执行流程,并在函数调用堆栈向上逐层返回,直到遇到recover函数或程序终止为止。

而recover函数的作用就是捕获这个panic,并恢复正常的执行流程。在Gin框架中,提供了recover中间件来自动捕获panic,并转换为HTTP 500错误返回给客户端。

使用

使用recover中间件非常简单,只需要在Gin路由中添加即可:

router := gin.Default()
router.Use(gin.Recovery())

需要注意的是,recover中间件应该在Gin路由中的第一个声明,以确保可以捕获所有的panic。

配合日志打印与埋点上报

在API开发中,当用户请求接口时,有时候会遇到一些问题,如访问url错误、参数错误、数据库连接超时等。虽然recover中间件可以避免由程序错误导致的panic,但仍然需要记录这些错误信息来协助问题的排查和定位。

因此,我们可以配合日志打印和埋点上报来记录这些错误。以日志打印为例,Gin框架提供了官方的Logger中间件,可以使用Logger来记录错误信息:


router := gin.Default()

// Logger 中间件将请求的URL、响应时间、响应状态码和请求的IP地址写入日志文件

router.Use(gin.Logger())

// Recover 中间件将 panic 转换为 500 错误,并写入日志文件

router.Use(gin.Recovery())

// 业务代码

router.GET("/api", func(c \*gin.Context) {

    // code

    if err != nil {

        // 某个函数抛出了 panic

        log.Printf("\[ERROR] - %v\n", err)

        c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{

            "message": "内部错误,请稍后重试",

        })

        return

    }

    // code

})

在上述代码中,我们使用log来记录错误信息,并在响应中返回了错误提示。这样我们就能及时的发现问题并进行排查了。

当然,我们还可以在记录错误信息的同时上传到埋点工具中,例如Sentry、Zipkin等,来实现自动的错误上报和监控。

recover在开源项目中的使用

recover中间件在开源项目中广泛应用,例如Prometheus、etcd、Kubernetes等项目中都有使用。

以etcd为例,它使用recover中间件捕获所有的panic,并在日志中记录错误信息,如下所示:

func (s *EtcdServer) recoverAndLog(rctx rpctypes.Context, w http.ResponseWriter, req *http.Request) {

    data, err := ioutil.ReadAll(req.Body)

    if err != nil {

        writeError(w, rctx, err)

        return

    }

    defer func() {

        if v := recover(); v != nil {

            log.Printf("panic: %v", v)

            writeError(w, rctx, fmt.Errorf("panic: %v", v))

        }

    }()

    // code

}

在该函数中,使用了defer关键字调用recover函数捕获panic,并使用log记录错误信息并返回错误提示。

总结

通过Gin框架中的recover中间件,我们可以方便的捕获和处理程序运行时的错误,从而提高了API服务的稳定性和可靠性。同时,配合日志打印和埋点上报,可以更好地记录错误信息和辅助问题的排查和解决。在开源项目中,recover中间件也被广泛应用,并帮助了很多项目实现了稳定的运行。

转载自:https://juejin.cn/post/7241134314501750842
评论
请登录