官方文档:https://godoc.org/github.com/gin-gonic/gin
官方地址:https://github.com/gin-gonic/gin
func main() {
//创建一个无中间件路由
router := gin.New()
router.Run()
}
func main() {
// 默认启动方式,包含 Logger、Recovery 中间件
router:=gin.Default()
router.GET("/", func(context *gin.Context) {
context.JSON(200,gin.H{
"goods_name":"牛奶",
})
})
router.Run()
}
结论: 上图控制台输出便是gin.Logger中间件输出访问记录到控制台
//自定义中间件第1种定义方式
func CustomRouterMiddle1(c *gin.Context) {
t := time.Now()
fmt.Println("我是自定义中间件第1种定义方式---请求之前")
//在gin上下文中定义一个变量
c.Set("example", "CustomRouterMiddle1")
//请求之前
c.Next()
fmt.Println("我是自定义中间件第1种定义方式---请求之后")
//请求之后
//计算整个请求过程耗时
t2 := time.Since(t)
log.Println(t2)
}
//自定义中间件第2种定义方式
func CustomRouterMiddle2() gin.HandlerFunc{
return func(c *gin.Context) {
t := time.Now()
fmt.Println("我是自定义中间件第2种定义方式---请求之前")
//在gin上下文中定义一个变量
c.Set("example", "CustomRouterMiddle2")
//请求之前
c.Next()
fmt.Println("我是自定义中间件第2种定义方式---请求之后")
//请求之后
//计算整个请求过程耗时
t2 := time.Since(t)
log.Println(t2)
}
}
func main() {
r := gin.New()
//测试时下面两个中间件选择一个,注释一个
r.Use(CustomRouterMiddle1)
r.Use(CustomRouterMiddle2())
r.GET("/test", func(c *gin.Context) {
example := c.MustGet("example").(string)
//
log.Println(example)
})
// 监听本地8080端口
r.Run(":8080")
}
访问 http://localhost:8080/test 效果图1:
访问 http://localhost:8080/test 效果图2:
结论: 第1种和第2种定义方式实质上都是一样的,都是定义一个参数类型为*gin.Context的函数。相对而言第1种不需要加(),更加简洁,个人推荐第1种。
还有一个就是大家可以看到效果图1和效果图2的打印顺序不一样,按照代码的语句顺序效果图1才是正确的,但是效果图2也没错。原因是这段代码的执行时间很短,4个输出语句都处于竞争状态,谁先抢到就运行一个时间片,然后才能轮到其他输出语句到达下一个时间片再抢,所以,结果不会唯一。这是本人对于这个的理解,等以后深入了解源码再和大家分享,如果有错,欢迎指出。
func RouterMiddle1(c *gin.Context) {
fmt.Println("我是路由中间件1")
}
func RouterMiddle2(c *gin.Context) {
fmt.Println("我是路由中间件2")
}
func oneRouterMiddleHandle() gin.HandlerFunc{
return func(c *gin.Context) {
fmt.Println("我是业务处理函数")
}
}
func main() {
//创建一个无中间件路由
router := gin.New()
// 对于每个路由中间件,您可以添加任意数量的路由中间件
router.GET("/oneRouterMiddle", RouterMiddle1,RouterMiddle2,oneRouterMiddleHandle())
// 默认监听本地 0.0.0.0:8080 即localhost:8080 或 127.0.0.1:8080
router.Run()
}
结论: 从上图可以看出单个路由的中间件是可以添加多个的,并按照添加的函数顺序执行的,所以我们把业务函数放在最后一个
func GroupRouterGoodsMiddle1(c *gin.Context) {
fmt.Println("我是goods路由组中间件1")
}
func GroupRouterGoodsMiddle2(c *gin.Context) {
fmt.Println("我是goods路由组中间件2")
}
func GroupRouterOrderMiddle1(c *gin.Context) {
fmt.Println("我是order路由组中间件1")
}
func GroupRouterOrderMiddle2(c *gin.Context) {
fmt.Println("我是order路由组中间件2")
}
func main() {
//创建一个无中间件路由
router := gin.New()
router.Use(gin.Logger())
//第1种路由组使用方式 可以添加多个处理函数 但是不知道为什么 官方举例的这第一种方式用不了
router.Group("/goods", GroupRouterGoodsMiddle1, GroupRouterGoodsMiddle2)
router.GET("/goods/add", func(context *gin.Context) {
fmt.Println("/goods/add")
})
//第2种路由组使用方式
orderGroup := router.Group("/order")
orderGroup.Use(GroupRouterOrderMiddle1, GroupRouterOrderMiddle2)
{
orderGroup.GET("/add", func(context *gin.Context) {
fmt.Println("/order/add")
})
orderGroup.GET("/del", func(context *gin.Context) {
fmt.Println("/order/del")
})
//orderGroup下再嵌套一个testGroup
testGroup:=orderGroup.Group("/test", func(context *gin.Context) {
fmt.Println("order/test下的中间件")
})
testGroup.GET("/test1", func(context *gin.Context) {
fmt.Println("order/test/test1的函数")
})
}
router.Run()
}
访问 http://localhost:8080/order/add
访问 http://localhost:8080/order/del
访问order下不存在的路由,显示404, 并且中间件不执行
访问 http://localhost:8080/order/test/test1
结论1: 填写正确的路由组和路由,中间件先执行,并按照传入函数的顺序执行。
结论2: 填写正确的路由组,错误的路由,中间件不执行,并返回404错误。
结论3: 路由组中还可以嵌套路由组
func GlobalMiddle(c *gin.Context){
fmt.Println("我是全局中间件")
}
func main() {
//创建一个无中间件路由
router := gin.New()
//使用自定义的全局中间件
router.Use(GlobalMiddle)
router.GET("/", func(context *gin.Context) {
fmt.Println("我是/")
})
router.Run()
}
这里我就不用代码展示了。大家在前面代码上测试下就行了,这里直接告诉大家结果。
结论: 全局中间件 > 路由组中间件 > 路由中间件
全局中间件最先执行
上图是官方示例,在第1种路由组使用方式,实际测试用不了。不知道是我太菜还是真是官方的bug,如果有小伙伴发现什么可以和我评论交流。