解决方案(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(¶m) // 会根据content-type自动识别json,xml,formc.BindJSON(¶m) // 按照json来解析参数c.BindXML(¶m)c.BindForm(¶m)
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(¶m); 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(¶m);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)