G

[Golang]Gin框架 9.中间件

RoLingG 2023-10-11

中间件和路由

​ 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")
}
PREV
[Golang]Gin框架 8.返回第三方获取的数据
NEXT
[Golang]Gin框架 10.路由分组和中间件

评论(0)

发布评论