分享

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

 印度阿三17 2021-03-19

介绍

HTTP服务框架,简单易用。

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

1. helloworld

package main

import(
    "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})
}

// 写法1
r.Use(middleware)

// 写法2
r.POST("/hello", middleware, handler)

// 写法3
g := r.Group("")
g.Use(middleware)
g.GET()
g.GET()

3. 绑定参数

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

  • query参数

GET /user-info/?page=1&size=100

// 如果page有值,则取page,如果没值,则取默认值1
page :=c.DefaultQuery("page",1)
// 如果size有值,则取size,如果没值,则去默认值10
size := 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,form
c.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后,不同的业务通过以下方式进行分包,避免团队开发时合并冲突。

    // shop
shopRouter.HTTPRouter(r)
// pay
payRouter.HTTPRouter(r)
// activity
activityRouter.HttpRouter(r)
// user
userRouter.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

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多