Golang实现自定义recovery中间件

 更新时间:2023年09月06日 08:27:46   作者:路多辛  
在 Golang 的 Web 项目中,自定义 recovery 中间件是一种常见的做法,用于捕获并处理应用程序的运行时错误,下面我们就来看看具体如何实现吧

为什么需要实现自定义 recovery 中间件

在 Golang 的 Web 项目中,自定义 recovery 中间件是一种常见的做法,用于捕获并处理应用程序的运行时错误,以避免整个应用程序崩溃并返回对应格式的响应数据。

很多三方 web 框架(例如 gin、echo)都提供了官方实现的 recovery 中间件,但是官方实现的中间件并不一定能满足自己的需求。例如 gin 官方提供的 recovery 中间件,发生 panic 后会将当前请求的标准状态码置为 500,body 置为空。但是这样的返回数据与格式可能会和自己的项目要求不一致。例如,项目发生 panic 后是要求标准状态码依然返回 200,body 值为 {"code":-1, "data":nil,"msg":"xxx"},这种场景下,就需要实现自己的 recovery 中间件了。

如何实现自定义 recovery 中间件

如果使用 gin 框架的话,就非常简单了,因为 gin 提供了完善的中间件功能,遵守 gin 的要求实现满足自己项目的功能就可以了,简单示例代码如下:

package main
import (
    "github.com/gin-gonic/gin"
    "log"
    "net/http"
    "runtime"
)
func Recovery() gin.HandlerFunc {
    return func(c *gin.Context) {
        defer func() {
            if err := recover(); err != nil {
                const size = 64 << 10
                stack := make([]byte, size)
                stack = stack[:runtime.Stack(stack, false)]
                log.Printf("[GinPanic] %s\n", string(stack))
                c.JSON(http.StatusOK, struct {
                    Code int         `json:"code"`
                    Data interface{} `json:"data"`
                    Msg  string      `json:"msg"`
                }{
                    Code: -1,
                    Data: nil,
                    Msg:  "server panic",
                })
                c.Abort()
            }
        }()
        c.Next()
    }
}

使用示例如下:

package main
import (
    "github.com/gin-gonic/gin"
    "runtime"
)
func main() {
    r := gin.New()
    r.Use(Recovery())
    r.GET("/test", func(c *gin.Context) {
        panic("Oops! Something went wrong.")
    })
    r.Run(":8080")
}

运行起来后,访问 /test 触发 panic 后返回了预期的结果,如下:

$ curl http://127.0.0.1:8080/test
{"code":-1,"data":null,"msg":"server panic"}

接下来再看一个基于原生包  net/http 的一个示例,代码如下:

package main
import (
    "fmt"
    "log"
    "net/http"
    "runtime/debug"
)
// 自定义的recovery中间件
func recoveryMiddleware(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        defer func() {
            if err := recover(); err != nil {
                // 打印错误信息
                log.Println("[Recovery] Panic:", err)
                // 打印堆栈跟踪信息
                log.Printf("[Recovery] Stack Trace:\n%s\n", debug.Stack())
                // 返回一个适当的错误响应给客户端
                fmt.Fprintf(w, `{"code":-1,"data":null,"msg":"server panic"}`)
            }
        }()
        // 继续处理下一个中间件或路由处理函数
        next.ServeHTTP(w, r)
    })
}
// 示例的处理函数
func helloHandler(w http.ResponseWriter, r *http.Request) {
    panic("Oops! Something went wrong.") // 模拟一个错误
    w.Write([]byte("Hello, Recovery Middleware!"))
}
func main() {
    // 创建一个多路复用器
    mux := http.NewServeMux()
    // 注册中间件
    mux.Handle("/test", recoveryMiddleware(http.HandlerFunc(helloHandler)))
    // 创建服务器
    server := &http.Server{
        Addr:    ":8080",
        Handler: mux,
    }
    // 启动服务器
    log.Println("Server is running on http://localhost:8080")
    log.Fatal(server.ListenAndServe())
}

小结

Web 应用程序在运行时遇到错误并抛出 panic 时,自定义的 recovery 中间件将会捕获panic 并记录对应的错误和堆栈信息,避免应用程序崩溃,并向客户端发送适当的错误响应数据。对于文本的示例,可以根据自己的实际需求进行调整和扩展来实现自定义的 recovery 中间件。

到此这篇关于Golang实现自定义recovery中间件的文章就介绍到这了,更多相关go recovery内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 一文带你了解Go语言标准库strings的常用函数和方法

    一文带你了解Go语言标准库strings的常用函数和方法

    strings 库包含了许多高效的字符串常用操作的函数和方法,巧用这些函数与方法,能极大的提高我们程序的性能。本文就来和大家分享一下Go标准库strings的常用函数和方法,希望对大家有所帮助
    2022-11-11
  • Go语言扫描目录并获取相关信息的方法

    Go语言扫描目录并获取相关信息的方法

    这篇文章主要介绍了Go语言扫描目录并获取相关信息的方法,实例分析了Go语言操作目录及文件的技巧,需要的朋友可以参考下
    2015-03-03
  • Go设计模式之模板方法模式讲解和代码示例

    Go设计模式之模板方法模式讲解和代码示例

    模版方法是一种行为设计模式, 它在基类中定义了一个算法的框架, 允许子类在不修改结构的情况下重写算法的特定步骤,本文将通过代码示例给大家详细的介绍一下Go模板方法模式,需要的朋友可以参考下
    2023-08-08
  • 如何在 Go语言中使用日志包

    如何在 Go语言中使用日志包

    这篇文章主要介绍了如何在 Go语言中使用日志包,日志文件就是一种快速找到这些 bug,更好地了解程序工作状态的方法,下文基于go语言介绍该详细需要的小伙伴可以参考一下
    2022-04-04
  • 使用Golang实现AES加解密的代码示例

    使用Golang实现AES加解密的代码示例

    在现代的数据安全中,加密和解密是极其重要的一环,其中,高级加密标准(AES)是最广泛使用的加密算法之一,本文将介绍如何使用Golang来实现AES加密和解密,需要的朋友可以参考下
    2024-04-04
  • 详解Go语言如何使用标准库sort对切片进行排序

    详解Go语言如何使用标准库sort对切片进行排序

    Sort 标准库提供了对基本数据类型的切片和自定义类型的切片进行排序的函数。今天主要分享的内容是使用 Go 标准库 sort 对切片进行排序,感兴趣的可以了解一下
    2022-12-12
  • Go语言线程安全之互斥锁与读写锁

    Go语言线程安全之互斥锁与读写锁

    这篇文章主要介绍了Go语言线程安全之互斥锁与读写锁,互斥锁是为了并发的安全,在多个goroutine共同工作的时候,对于共享的数据十分不安全,而读写锁效率革命,使用锁的时候,安全与效率往往需要互相转换,下文详细内容,需要的小伙伴可以参考一下
    2022-02-02
  • 通过案例简单聊聊为什么说Go中的字符串是不能被修改的

    通过案例简单聊聊为什么说Go中的字符串是不能被修改的

    在接触Go这么语言,可能你经常会听到这样一句话,对于字符串不能修改,可能你很纳闷,日常开发中我们对字符串进行修改也是很正常的,为什么又说Go中的字符串不能进行修改呢,本文就来通过实际案例给大家演示,为什么Go中的字符串不能进行修改
    2023-07-07
  • Go中的应用配置管理详解

    Go中的应用配置管理详解

    这篇文章主要为大家介绍了Go中的应用配置管理详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-09-09
  • 服务器端Go程序对长短链接的处理及运行参数的保存

    服务器端Go程序对长短链接的处理及运行参数的保存

    这篇文章主要介绍了服务器端Go程序对长短链接的处理及运行参数的保存,这里针对使用Go语言编写的Socket服务器进行实例说明,需要的朋友可以参考下
    2016-03-03

最新评论