Go语言学习记录之四:Gin框架 | 青训营笔记

142 阅读2分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 4 天

Gin

Gin是一款基于Go语言实现的Web框架,在Gihub上Star数达近66k,非常建议学习一下。

以下为Gin的一个简单例子:

package main

import "github.com/gin-gonic/gin"

func main() {
	r := gin.Default()
	r.GET("/hello", func(c *gin.Context) {
		c.String(200, "hello world")
	})
	r.Run()
}

启动后通过浏览器打开网址127.0.0.1:8080/hello,即可看到hello world

创建服务

有两种创建gin服务实例的方式:gin.Defaultgin.New。通常使用前者即可,它在后者的基础上搭配了loggerrecovery两个中间件,能够看到请求的日志并保证服务的稳定性。

创建路由

路由的基本使用如下: 路径 + 处理函数 + 中间件

userGroup := r.Group("user")
userGroup.POST("login", UserApi.Login)
userGroup.GET("info", UserApi.Info, AuthMiddleware())

其中路由路径分为好几类,

  • 静态路由 /user
  • 参数路由 /user/:id
  • 通配符路由 /user/*

编写处理函数

处理函数的例子:

// define
type LoginReq struct {
    Username string `form:"username" binding:"required"`
    Password string `form:"password" binding:"required"`
}

// user
func (u *userApi) Login(c *gin.Context) {
    var req define.LoginReq

    if err := c.ShouldBindQuery(&req); err != nil {
        response.Resp(c, define.LoginRes{
            Errno: *response.ErrValidation,
        })
    } else {
        response.Resp(c, service.UserService.Login(req))
    }
}

// response
func Resp(ctx *gin.Context, data interface{}) {
    ctx.JSON(http.StatusOK, data)
}

几种获取路由请求参数的方式:

  • c.Query('name') 用于获取url?name=123获取query参数
  • c.Params('name') 用于针对路由/user/:name获取路由参数
  • c.PostFForm('name') 用于获取POST请求的body参数

上面的示例中用到了ShouldBindQuery函数,用于借助req结构体中的tag来进行校验,可以填入更多的校验信息,可参考文章

几种写入路由返回值的方式:

  • c.JSON 返回对象、结构体等
  • c.String 返回字符串
  • c.HTML 返回html模板

配置中间件

logger

如前面所说gin.Default中配置了默认的两个中间件,但是如果想自定义日志该如何处理呢?

需求一:日志写入文件

writer, _ := os.OpenFile(path, os.O_CREATE|os.O_APPEND, 0666)
gin.DefaultWriter = io.MultiWriter(writer, os.Stdout)

需求二:自定义日志格式

如果想自定义日志的内容我们可以返回一个这样的格式:

func logFormat(param gin.LogFormatterParams) string {
    // your custom format
    return fmt.Sprintf("[%s] - %s \"%s %s %s %d %s \"%s\" %s\"\n",
        param.ClientIP,
        param.TimeStamp.Format(time.RFC3339Nano),
        param.Method,
        param.Path,
        param.Request.Proto,
        param.StatusCode,
        param.Latency,
        param.Request.UserAgent(),
        param.ErrorMessage,
    )
}

r.Use(gin.LoggerWithFormatter(logFormat))

auth

在后端常常需要进行用户认证,增加用户认证的中间件,下面的示例中借助了jwt来进行校验:

func AuthMiddleware() gin.HandlerFunc {
    return func(c *gin.Context) {
        token := c.Query("token")
        claims, err := jwt.ParseToken(token)
        if err != nil {
            response.Resp(c, response.ErrToken.Extend(err))
            c.Abort()
        } else {
            c.Set("user", claims.User)
        }
    }
}

有几点需要注意:

  • 上面的token从query参数获取,一般可以放入header
  • 一旦中间件出错不希望继续执行,调用函数c.Abort()
  • 执行成功后,可以将一些信息通过c.Set存储到这个路由请求的上下文中。