gin定位:一款高性能的go web框架
基本实践一次搞定!
目录
项目结构
main.go(多组路由)
以order.go测试GET各请求
以customer.go测试POST/PUT请求
调用目标API前先校验(多处理器)
多路由API执行前校验
项目结构
main.go(多组路由)
分两组路由,验证路由分组功能
package main
import (
"gin-coms/config"
"gin-coms/routers"
"github.com/gin-gonic/gin"
)
func main() {
router := gin.Default()
// 第一组路由:以/api开头
apiGroup := router.Group("/api")
{
routers.CusRoute(apiGroup)
routers.OrderRoute(apiGroup)
}
// 第二组路由:以/other开头
otherGroup := router.Group("/other")
{
routers.OtherRoute(otherGroup)
}
//config.InitMysql()
router.Run(config.ComsAddress + ":" + config.ComsPort)
}
以order.go测试GET各请求
package routers
import (
"fmt"
"gin-coms/model"
"github.com/gin-gonic/gin"
"net/http"
)
func OrderRoute(group *gin.RouterGroup) {
group.GET("/order", OrderList)
group.GET("/order/:ID", OrderDetail)
// URL的问号会带参数name
// http://localhost:8000/api/orderByName?name=无名
group.GET("/orderByName", OrderByName)
}
func OrderByName(c *gin.Context) {
name := c.Query("name") //获取URL参数
// 也可通过 c.ShouldBindQuery(&xx) 直接绑定到结构体对象,但需要绑定的字段中加form标签
fmt.Println("您要查询的订单名称是:", name)
c.JSON(http.StatusOK, "hello 这里是/api/orderByName路由,您要查询的订单名称是:"+name)
//c.String(http.StatusOK, "hello 这里是/api/order路由")
}
func OrderDetail(c *gin.Context) {
id := c.Param("ID") //获取URL路径参数
fmt.Println("您要查询的是", id, "号订单。")
c.JSON(http.StatusOK, "hello 这里是/api/order/:ID路由,您要查询的是"+id+"号订单。")
//c.String(http.StatusOK, "hello 这里是/api/order路由")
}
func OrderList(c *gin.Context) {
var orderList []model.Order
order1 := model.Order{Name: "订单1", OrderPrice: 88}
order2 := model.Order{Name: "订单2", OrderPrice: 99}
orderList = append(orderList, order1, order2)
c.String(http.StatusOK, "hello 这里是/api/order路由,此处返回订单列表:", orderList)
// 如果要返回自定义结构体类型ReturnStruct,需要改源码,在type HandlerFunc func(*Context)后加返回值ReturnStruct即可。
//return model.ReturnStruct{Code:http.StatusOK,Message:"hello 这里是/api/order路由,此处返回订单列表!",Data:orderList}
}
URL1:http://localhost:8000/api/orderByName?name=无名
URL2:http://localhost:8000/api/order/9
order列表:
控制台日志如下:
以customer.go测试POST/PUT请求
分别以两种方式获取请求体参数
package routers
import (
"fmt"
"gin-coms/model"
"github.com/gin-gonic/gin"
"log"
"net/http"
)
func CusRoute(group *gin.RouterGroup) {
group.POST("/cus", CreateCustomer)
group.PUT("/cus", UpdateCustomer)
}
func CreateCustomer(c *gin.Context) {
var cus model.Customer
err := c.BindJSON(&cus) // 获取请求体参数,请求头为application/json
if err != nil {
log.Println(err.Error())
}
fmt.Println("用户", cus, "已创建。")
c.JSON(http.StatusOK, "用户已创建。")
}
func UpdateCustomer(c *gin.Context) {
name := c.PostForm("name") // 获取请求体参数,请求头为application/x-www-form-urlencoded
gender := c.PostForm("gender")
fmt.Println("用户", name," ",gender, "已修改。")
c.JSON(http.StatusOK, "用户已修改。")
}
测试POST
测试PUT
控制台打印:
调用目标API前先校验(多处理器)
我想在走进orderList接口之前先执行下CheckOrder,CheckOrder里面是我自己的校验逻辑,,应该怎么做?
修改order.go中的orderlist路由,增加CheckOrder处理器:
group.GET("/order",CheckOrder, OrderList) // 增加一个处理器
func CheckOrder(c *gin.Context){
fmt.Println("---进入check函数---")
if c.Request.Header.Get("token") == "enyduuamlm2cdcs=="{
fmt.Println("验证通过!")
return
}
c.Abort() // 执行该行之后下一个处理器将不会执行
c.JSON(http.StatusUnauthorized,"验证失败!")
}
以正确情况验证一下:
日志打印:
如果不按CheckOrder中的校验规则来,或者header中有token字段但内容错误:
即,错误情况下报401,请求终止。
上面这种方式对于单个需要校验的处理器而言还行,如果是大规模路由呢?
多路由API执行前校验
以第二组路由other模块试试。other模块有两个模块的路由:OneRoute和OtherRoute,目前简便起见各只有一个接口,我只想让OtherRoute下的所有路由走CheckByToken处理器,OneRoute不用验证就能访问,应该怎么做?
修改代码,变动如下:
func main() {
router := gin.New()
router.Use(gin.Logger())
router.Use(gin.Recovery())
// 第一组路由:以/api开头
apiGroup := router.Group("/api")
{
routers.CusRoute(apiGroup)
routers.OrderRoute(apiGroup)
}
// 第二组路由:以/other开头
otherGroup := router.Group("/other")
{ routers.OneRoute(otherGroup)
// 可以放多个中间件,如otherGroup.Use(CheckByToken(),CheckBySession()),按顺序执行
// CheckByToken()对otherGroup.Use(CheckByToken())之后的路由起作用
otherGroup.Use(CheckByToken())
routers.OtherRoute(otherGroup)
}
//config.InitMysql()
router.Run(config.ComsAddress + ":" + config.ComsPort)
}
func CheckByToken() gin.HandlerFunc{
return func(c *gin.Context){
fmt.Println("---进入CheckByToken函数---")
if c.Request.Header.Get("token") == "token-abcde"{
fmt.Println("验证token成功!")
// 验证通过时继续往下走访问下一个中间件
c.Next()
} else {
// 验证不通过时请求终止
c.Abort()
c.JSON(http.StatusUnauthorized,"验证失败!")
}
}
}
func CheckBySession() gin.HandlerFunc{
return func(c *gin.Context){
}
}
other路由模块:
func OtherRoute(group *gin.RouterGroup){
group.GET("/test", OtherList)
}
func OneRoute(group *gin.RouterGroup){
group.GET("/one", oneList)
}
func oneList(c *gin.Context){
fmt.Println("成功进入oneList接口")
c.String(http.StatusOK, "hello, 这里是/other/one路由")
}
func OtherList(c *gin.Context){
fmt.Println("成功进入OtherList接口")
c.String(http.StatusOK, "hello, 这里是/other/test路由")
}
访问/other/test并且带正确token验证一下:
访问/other/test并且带错误token验证一下:
上面两步控制台打印如下:
即用户访问/other/test时肯定会先执行CheckByToken处理器,接下来分别以正确和不正确的token来
验证下/other/one:
控制台日志:
即,根本不会进CheckByToken处理器,它对/other/one接口(OneRoute下的所有路由)是没有任何作用的,那么上面的做法就得到了验证,我们的目的也就达成了。
gin的多处理器逻辑这块和马卡龙(macaron)是非常类似的。