这是我参与「第五届青训营 」伴学笔记创作活动的第 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.Default
和 gin.New
。通常使用前者即可,它在后者的基础上搭配了logger
和recovery
两个中间件,能够看到请求的日志并保证服务的稳定性。
创建路由
路由的基本使用如下: 路径 + 处理函数 + 中间件
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
存储到这个路由请求的上下文中。