前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >「Go框架」gin框架是如何处理panic的?

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

作者头像
Go学堂
发布2023-08-28 14:47:52
6870
发布2023-08-28 14:47:52
举报
文章被收录于专栏:Go工具箱

大家好,我是渔夫子

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

代码语言:javascript
复制
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")
}

panic被描述为不可处理的错误。在web服务中就是服务会崩溃。当然,这在生产环境下是不可接受的。那么,如何能够做到发生panic时技能捕获该panic又能让服务继续健康运行呢?

这就是golang中提供的recover函数了。recover函数能够捕获Panic错误并恢复程序的正常运行。接下来,我们看下recover函数在gin框架中是如何应用的。

首先,要提到的就是gin框架中的recovery中间件。在gin中,是通过使用该中间件来捕获panic,并保证服务不down机的。如果使用gin.Default()函数进行构建gin对象,那么默认就注册了Recovery中间件。

代码语言:javascript
复制
func Default() *Engine {
 debugPrintWARNINGDefault()
 engine := New()
    //  注册了Recovery中间件
 engine.Use(Logger(), Recovery())
 return engine
}

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

Recovery()函数定义如下:

代码语言:javascript
复制
func Recovery() HandlerFunc {
 return RecoveryWithWriter(DefaultErrorWriter)
}

这里的DefaultErrorWriter是默认的输出端,即os.Stderr。即指错误的输出到什么地方。

接下来看RecoveryWithWriter函数中的实现

代码语言:javascript
复制
// 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,我们看下它的实现:

代码语言:javascript
复制
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框架也有同样的机制,实现原理也是一样的。

特别说明:你的关注,是我写下去的最大动力。点击下方公众号卡片,直接关注。关注送《100个go常见的错误》pdf文档、经典go学习资料。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2023-05-17,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Go学堂 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
消息队列 TDMQ
消息队列 TDMQ (Tencent Distributed Message Queue)是腾讯基于 Apache Pulsar 自研的一个云原生消息中间件系列,其中包含兼容Pulsar、RabbitMQ、RocketMQ 等协议的消息队列子产品,得益于其底层计算与存储分离的架构,TDMQ 具备良好的弹性伸缩以及故障恢复能力。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档