中间件和路由
Gin框架允许开发者在处理请求的过程中,加入用户自己的钩子(Hook)函数。这个钩子函数就叫中间件。
中间件适合处理一些公共的业务逻辑,比如登录认证、权限校验、数据分页、记录日志、耗时统计等,即比如:如果访问一个网页的话,不管访问什么路径都需要进行登录,此时就需要为所有路径的处理函数进行统一一个中间件。
Gin中的中间件必须是一个gin.HandlerFunc
类型
单独注册中间件
请求中间件、响应中间件(与基础中间件混杂在一起)
package main
import (
"fmt"
"github.com/gin-gonic/gin"
)
// 这里就是一个视图,现在叫中间件
func test(c *gin.Context) {
fmt.Println("test ...")
//这里写的其实就是等价于回去运用了这个func的地方里面写
c.JSON(200, gin.H{"msg": "test访问成功"})
//用了c.Abort(),后续的内容变不会被实现出来,会发现原来GET那里的另一个func等后续的内容无了,被Abort拦截了,后续中间件不再执行
//c.Abort()
}
func test1(c *gin.Context) {
fmt.Println("test1 ...")
//这里写的其实就是等价于回去运用了这个func的地方里面写
c.JSON(200, gin.H{"msg": "test1访问成功"})
//c.Abort()
fmt.Println("test1 ... in")
//控制中间件是否继续往下走,在它之前的就是请求中间件,在它之后的就是响应中间件
//会发现in是从前往后入,而out时是从后往前出,洋葱模型?
//如果中间出现Abort(),则会在相应位置之后的中间件都不响应,提前进入相应位置前的中间件的out流(意思是提前响应Abort前面的,后面的不响应)
//注意Abort()的位置,一般在Next()前,Next()之后Abort是没有意义的,因为已经响应了
c.Next()
fmt.Println("test1 ... out")
}
func test2(c *gin.Context) {
fmt.Println("test2 ...")
//这里写的其实就是等价于回去运用了这个func的地方里面写
c.JSON(200, gin.H{"msg": "test2访问成功"})
//c.Abort()
fmt.Println("test2 ... in")
c.Next()
fmt.Println("test2 ... out")
}
func main() {
router := gin.Default()
//*gin。Context里面是一个handler,这个handler是一个切片,意味着这里可以写多个func
//router.GET("/", func(c *gin.Context) {
// c.JSON(200, gin.H{"msg": "访问成功index"})
//}, func(c *gin.Context) {
// fmt.Println("1")
//}, func(c *gin.Context) {
// fmt.Println("2")
//}, func(c *gin.Context) {
// fmt.Println("3")
//})
//先运行test,再运行func里面的内容,有先后顺序,从前往后
router.GET("/", test, func(c *gin.Context) {
fmt.Println("index ...")
//↓内外部写法等价
//c.JSON(200, gin.H{"msg": "test访问成功"})
c.JSON(200, gin.H{"msg": "index访问成功"})
//视图里也可以Abort()
//c.Abort()
fmt.Println("index ... in")
c.Next()
fmt.Println("index ... out")
}, test1, test2)
router.Run(":80")
}
全局注册中间件
我们设置中间件其实就是为了给一系列的路由写一个通用的逻辑,例如权限校验和ip封锁等。
package main
import (
"fmt"
"github.com/gin-gonic/gin"
)
func mid1(c *gin.Context) {
fmt.Println("mid1 ... in")
c.Next()
fmt.Println("mid1 ... out")
}
func mid2(c *gin.Context) {
fmt.Println("mid2 ... in")
c.Next()
fmt.Println("mid2 ... out")
//这里Next()还是一样,该怎么走怎么走
}
func main() {
router := gin.Default()
//如果我们想用全局中间件,有个方法Use()
//router.Use(mid1)
//会发现mid1 ... in无论哪个路径都会被输出,这就是全局中间件
//多个全局中间件
router.Use(mid1, mid2)
//会发现mid1 ... in和mid2 ... in无论哪个路径都会被输出
router.GET("/mid1", func(c *gin.Context) {
c.JSON(200, gin.H{"msg": "mid1访问成功"})
})
router.GET("/mid2", func(c *gin.Context) {
c.JSON(200, gin.H{"msg": "mid2访问成功"})
})
router.Run(":80")
}
中间件传递数据
使用一个set设置一个key-value
后续中间件使用Get接受数据
package main
import (
"fmt"
"github.com/gin-gonic/gin"
)
//func mid1(c *gin.Context) {
// fmt.Println("mid1 ... in")
// c.Next()
// fmt.Println("mid1 ... out")
//}
//
//func mid2(c *gin.Context) {
// fmt.Println("mid2 ... in")
// c.Next()
// fmt.Println("mid2 ... out")
// //这里Next()还是一样,该怎么走怎么走
//}
type Student struct {
Name string
Age int
}
func mid3(c *gin.Context) {
fmt.Println("mid3 ... in")
//设置数据,名为name,数据值为RoLingG,值是any类型,传啥都行
c.Set("name", "RoLingG")
c.Set("student", Student{
Name: "RoLingG",
Age: 18,
})
}
func main() {
router := gin.Default()
//如果我们想用全局中间件,有个方法Use()
//router.Use(mid1)
//会发现mid1 ... in无论哪个路径都会被输出,这就是全局中间件
//多个全局中间件
//router.Use(mid1, mid2)
//会发现mid1 ... in和mid2 ... in无论哪个路径都会被输出
//router.GET("/mid1", func(c *gin.Context) {
// c.JSON(200, gin.H{"msg": "mid1访问成功"})
//})
//router.GET("/mid2", func(c *gin.Context) {
// c.JSON(200, gin.H{"msg": "mid2访问成功"})
//})
router.Use(mid3)
router.GET("/", func(c *gin.Context) {
//获取mid3设置的数据,会返还值+一个bool值,bool值判断值是否存在
fmt.Println("——————————————————")
fmt.Println(c.Get("name"))
name, ok := c.Get("name")
fmt.Println("name:", name)
fmt.Println("ok:", ok)
fmt.Println("——————————————————")
//如果不需要对数据进行处理,则不用断言,如果拿结构体的某一个值,则需要断言,底下这一行的user是any类型
student, ok := c.Get("student")
_student := student.(Student)
fmt.Println("student.Name:", _student.Name)
fmt.Println("student.Age", _student.Age)
fmt.Println("——————————————————")
c.JSON(200, gin.H{"msg": "mid3访问成功", "student": student})
})
router.Run(":80")
}
评论(0)