QBlog
Gin 路由封装,统一返回结构体,错误处理

Gin 路由封装,统一返回结构体,错误处理

2023/08/02 14:16
gogin
avatar

使用方法"封装"

一开始使用的方案是封装几个小方法来统一返回的结构体的 项目是字节青训营的项目,状态码就2个,所以还是挺好用的

我也习惯在dev模式和debug模式下返回error错误,方便定位问题~~ 也喜欢用可变参数来封装,这样比较简洁,也好扩展多返回几个或者不返回

go
func OK(c *gin.Context, data ...map[string]any) {
    res := gin.H{
        "status_code": statusOk,
        "status_msg":  "Success",
    }
    for d := range data {
        for k, v := range data[d] {
            res[k] = v
        }
    }
    c.JSON(http.StatusOK, res)
}

func Err(c *gin.Context, msg string, err ...error) {
    res := gin.H{
        "status_code": statusErr,
        "status_msg":  msg,
    }
    // 调试与开发模式,返回错误消息。
    if (flags.Dev || flags.Debug) && len(err) > 0 {
        errs := make([]string, len(err))
        for i, e := range err {
            if e != nil {
                errs[i] = e.Error()
            }
        }
        res["errmsg"] = errs
    }
    c.JSON(http.StatusOK, res)
}

// ErrParam 参数错误封装
func ErrParam(c *gin.Context, err ...error) {
    Err(c, "参数不正确", err...)
}

优点

  • 确实简单
  • 一眼就明白

缺点

  • 每次处理错误都需要在下面加个return,不然下面的也跑了一边
  • 路由方法感觉很乱,看着不舒服

使用装饰器封装

使用装饰器来实现统一返回体,简单好看,还方便

go
type MyHandler func(*gin.Context) (int, any)

// decorator 装饰器
func decorator() func(h MyHandler) gin.HandlerFunc {
    return func(h MyHandler) gin.HandlerFunc {
        return func(c *gin.Context) {
            code, data := h(c)
            req := gin.H{
                "status_code": code,
                "status_msg":  "",
            }
            if code == 0 {
                //判断数据类型
                if val, ok := data.(handlers.H); ok {
                    for k, v := range val {
                        req[k] = v
                    }
                }
                req["status_msg"] = "ok!"
                c.JSON(200, req)
            } else {
                switch data.(type) {
                case string:
                    req["status_msg"] = data
                case error:
                    //判断是否debug模式,是的话返回错误信息
                    if flags.Dev || flags.Debug {
                        req["errmsg"] = data.(error).Error()
                    }
                case handlers.MyErr:
                    e := data.(handlers.MyErr)
                    req["status_msg"] = e.Msg
                    //判断是否debug模式,是的话返回错误信息
                    if flags.Dev || flags.Debug {
                        errs := make([]string, 0, 10)
                        for i := range e.Errs {
                            errs = append(errs, e.Errs[i].Error())
                        }
                        req["errmsg"] = errs
                    }
                }

                c.JSON(http.StatusOK, req)
            }
        }
    }
}

func newRouter(group *gin.RouterGroup, method string, path string, handler MyHandler, handlers ...gin.HandlerFunc) {
    if handler != nil {
        // 未开发的路由传nil,不挂载
        group.Handle(method, path, append(handlers, decorator()(handler))...)
    }
}

这是路由处理那边的,这样我遇到错误就只需要 return Err("你没有登录") 也可以在后面带上err错误,正确的话就直接返回 return Ok(H{"id":666})

简洁多了,可读性也高了

go
func Ok(data any) (int, any) {
    return 0, data
}
func Err(msg string, errs ...error) (int, MyErr) {
    return 1, MyErr{msg, errs}
}
func ErrParam(errs ...error) (int, MyErr) {
    return 1, MyErr{"参数不正确", errs}
}

下面是路由挂载的使用方法

go
router := r.Group("douyin")
tester := r.Group("douyin")
tester.Use(middleware.Test())
// 视频类接口
{
  newRouter(router, "GET", "feed/", handlers.VideoGet)                     // 获取视频流
  newRouter(router, "POST", "publish/action/", handlers.VideoAction)       // 视频投稿
  newRouter(tester, "POST", "publish/actionUrl/", handlers.VideoActionUrl) // 视频投稿(测试接口)
  newRouter(router, "GET", "publish/list/", handlers.VideoList)            // 获取发布列表
}

Gin 路由封装,统一返回结构体,错误处理

https://ocyss.icu/article/skill/go/gin-routing-error-handling-structure

本文采用 CC BY-NC-SA 4.0 许可协议

转载请注明作者 Ocyss_04 及本文链接,禁止用于商业目的

评论