解决方案(6) http-gin的使用

介绍

HTTP服务框架,简单易用。

简称 类型 含义
r gin.IRouter 路由器对象。
c *gin.Context 请求上下文。
param Param 路由handler的入参绑定对象

1. helloworld

package mainimport(    "github.com/gin-gonic/gin")func main() {r :=gin.Default()    r.GET("/weather", func(c *gin.Context){c.JSON(200, gin.H{"tip_id":0, "tip": "晴朗"})    })    r.Run(":8080")}

2. 中间件

  • 写法1,在调用Use()之后的路由,都会执行这个中间件里的操作

  • 写法2,在路由中间的中间件,只会在该路由生效

  • 写法3,仅会在g对应的路由中生效。

var middleware = func(c *gin.Context){fmt.Printf("recv ip %s\n", c.ClientIP())    // c.Next() 放行        // c.Abort() 拦截住,请求终止并回复    // c.JSON(403, gin.H{"tip":"权限不足","tip_id":403})}// 写法1r.Use(middleware)// 写法2r.POST("/hello", middleware, handler)// 写法3g := r.Group("")g.Use(middleware)g.GET()g.GET()

3. 绑定参数

参数分为三种: query参数, body参数, param参数

  • query参数

GET /user-info/?page=1&size=100// 如果page有值,则取page,如果没值,则取默认值1page :=c.DefaultQuery("page",1)// 如果size有值,则取size,如果没值,则去默认值10size := c.DefaultQuery("size", 10)
  • param参数

r.GET("/user-info/:id/", func(c *gin.Context) {// 输出19    fmt.Println(c.Param("id"))})curl http://localhost:8080/user-info/19/
  • body参数

body有三种常见协议,xml,json,form。并且请求方法必须为POST。一般都用json

c.Bind(&param)    // 会根据content-type自动识别json,xml,formc.BindJSON(&param) // 按照json来解析参数c.BindXML(&param)c.BindForm(&param)

4. 回复

c.JSON(200, gin.H{"tip_id":0,    "tip":"和和"})

5. 标签 - tag

  • json 全golang通用的json标签,json(反)解析时,通过json的tag值匹配

  • binding 仅gin里校验该值是否为空值。空值时,BindJSON操作会返回错误。

func GetUserInfo(c *gin.Context) {type Param struct{// 匹配{"real_name":"猪"}        // 对不传real_name与{"real_name":""}都会报错        Realname string `json:"real_name" binding:"required"`    }        var param Param    if e:=c.Bind(&param); e!=nil {c.JSON(400, gin.H{"message": e.Error()})        return     }        ...}

tag仅使用binding,不使用其它的,减少DSL的产生。

6. 最佳实践

6.1 分包

  • 项目入口main.go声明了r后,不同的业务通过以下方式进行分包,避免团队开发时合并冲突。

// shopshopRouter.HTTPRouter(r)// paypayRouter.HTTPRouter(r)// activityactivityRouter.HttpRouter(r)// useruserRouter.HTTPRouter(r)

6.2 业务隔离

  • 业务和Control隔离开,方便做业务重用。比如http请求改造成grpc请求。

func GetUserInfo(c *gin.Context) {type Param struct{GameId int `json:"game_id" binding:"required"`        UserId int `json:"user_id" binding:"required"`    }    var param Param    if e:=c.Bind(&param);e!=nil {c.JSON(400, gin.H{"message":e.Error()})        return    }    // 实际获取的方法,必须分包在userService里完成,而不是在本函数完成    userInfo, _ :=userService.GetUserInfo(param.GameId, param.UserId)    c.JSON(200, gin.H{"data":userInfo, "tip_id":0})}

7. 注意事项

  • 业务返回码(statuscode)不要使用403以下的。不利于后期做健康检查,高可用。

  • 不要直接基于Control做业务编码,不利于后期做重要服务分离,协议转换。

  • 不要在tag里写魔法,顶多用一下json,xml,form,binding这四种tag

  • 路由不要时而/user 时而 /user/。 统一成一种。

  • 路由不要过度拆分,经常需要通过全文本搜索来匹配到对应的位置。

(0)

相关推荐