• 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 的要求实现满足自己项目的功能就可以了,简单示例代码如下:

    1. package main
    2. import (
    3. "github.com/gin-gonic/gin"
    4. "log"
    5. "net/http"
    6. "runtime"
    7. )
    8. func Recovery() gin.HandlerFunc {
    9. return func(c *gin.Context) {
    10. defer func() {
    11. if err := recover(); err != nil {
    12. const size = 64 << 10
    13. stack := make([]byte, size)
    14. stack = stack[:runtime.Stack(stack, false)]
    15. log.Printf("[GinPanic] %s\n", string(stack))
    16. c.JSON(http.StatusOK, struct {
    17. Code int `json:"code"`
    18. Data interface{} `json:"data"`
    19. Msg string `json:"msg"`
    20. }{
    21. Code: -1,
    22. Data: nil,
    23. Msg: "server panic",
    24. })
    25. c.Abort()
    26. }
    27. }()
    28. c.Next()
    29. }
    30. }

    使用示例如下:

    1. package main
    2. import (
    3. "github.com/gin-gonic/gin"
    4. "runtime"
    5. )
    6. func main() {
    7. r := gin.New()
    8. r.Use(Recovery())
    9. r.GET("/test", func(c *gin.Context) {
    10. panic("Oops! Something went wrong.")
    11. })
    12. r.Run(":8080")
    13. }

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

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

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

    1. package main
    2. import (
    3. "fmt"
    4. "log"
    5. "net/http"
    6. "runtime/debug"
    7. )
    8. // 自定义的recovery中间件
    9. func recoveryMiddleware(next http.Handler) http.Handler {
    10. return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    11. defer func() {
    12. if err := recover(); err != nil {
    13. // 打印错误信息
    14. log.Println("[Recovery] Panic:", err)
    15. // 打印堆栈跟踪信息
    16. log.Printf("[Recovery] Stack Trace:\n%s\n", debug.Stack())
    17. // 返回一个适当的错误响应给客户端
    18. fmt.Fprintf(w, `{"code":-1,"data":null,"msg":"server panic"}`)
    19. }
    20. }()
    21. // 继续处理下一个中间件或路由处理函数
    22. next.ServeHTTP(w, r)
    23. })
    24. }
    25. // 示例的处理函数
    26. func helloHandler(w http.ResponseWriter, r *http.Request) {
    27. panic("Oops! Something went wrong.") // 模拟一个错误
    28. w.Write([]byte("Hello, Recovery Middleware!"))
    29. }
    30. func main() {
    31. // 创建一个多路复用器
    32. mux := http.NewServeMux()
    33. // 注册中间件
    34. mux.Handle("/test", recoveryMiddleware(http.HandlerFunc(helloHandler)))
    35. // 创建服务器
    36. server := &http.Server{
    37. Addr: ":8080",
    38. Handler: mux,
    39. }
    40. // 启动服务器
    41. log.Println("Server is running on http://localhost:8080")
    42. log.Fatal(server.ListenAndServe())
    43. }

    小结

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

  • 相关阅读:
    【Linux】ubuntu系统root用户不能通过ssh连接
    算法学习打卡day41|栈和队列:栈和队列相互实现、括号匹配、逆波兰表达式、滑动窗口最大值问题、求前 K 个高频元素
    腌萝卜很好吃
    Ant Design入门、Ant Design Pro入门
    dsumtype的比较
    DNS协议隧道(1)
    React Server Component: 混合式渲染
    C#,计算图最大流量的福特-富尔克森(Ford Fulkerson)算法与源程序
    element plus tree组件 check-change 和 check属性的区别
    架构篇(七)安全架构
  • 原文地址:https://blog.csdn.net/luduoyuan/article/details/132702098