package main
import (
"fmt"
"github.com/gin-gonic/gin"
"net/http"
"time"
)
type Student struct {
Name string `json:"name"`
Country string `json:"country"`
City string `json:"city"`
}
// handlerfun 处理函数的格式
/*
func (group *RouterGroup) GET(relativePath string, handlers ...HandlerFunc) IRoutes {
return group.handle(http.MethodGet, relativePath, handlers)
}
*/
// 自定义中间件 注意: 中间件必须是一个handlerfunc 类型
func Myhandlerfun(c *gin.Context) {
fmt.Println("路由函数 start.....")
time.Sleep(3) // make this functinon sleep a secent so that we can see the diffirent clearly
c.JSON(http.StatusOK, gin.H{
"cotent": "ok",
})
}
// 自定义中间件:
func Mytestmi(c *gin.Context) {
fmt.Println("m1 start.....")
fmt.Println("---------------this is for middleware test----------")
ti := time.Now()
c.Next() // 调用后续处理的函数 包括后续的中间件。 所有后续中函数和中间件执行完了 以后,
timecost := time.Since(ti)
fmt.Printf("处理函数消耗的时间是%v\n ", timecost)
fmt.Println("中间件函数 Mytestmi 退出")
fmt.Println("m1 stop.....")
}
// 再定义一个中间件
func m2(c *gin.Context) {
fmt.Println("m2 start.....")
fmt.Println("--------------m2 test--------------")
//c.Abort() //阻止 后续的执行函数操作 查询结果 查询,路由函数正常执行, m3 没有执行。
}
// c.Abort() 阻止调用后续的执行函数。 再创建一个中间件,在上一个中间件中 c.Abort() ,然后看下 后续的中间件和 路由执行函数是否有执行。
func m3(c *gin.Context) {
fmt.Println("m3 start.....")
c.Set("hostname","v_jsonchang")
fmt.Println("----------------this is m3 test---------------")
fmt.Println("m3 stop.....")
}
// 是否登录判断的中间件
func authorMiddle(c *gin.Context) {
c.Next()
c.Abort()
/*
大致逻辑思路
if 是用户
c.Next()
else
c.Abort()0
*/
}
// 写法
func AuthorCheckMiddle(check bool) gin.HandlerFunc {
// 连接数据库
// 或者一些其他的准备工作[这部分在程序运行的时候就执行了]
/*
运行程序的时候的日志信息:
[GIN-debug] GET /index --> main.Myhandlerfun (4 handlers)
[GIN-debug] GET /home --> main.main.func1 (4 handlers)
[GIN-debug] GET /student/info --> main.main.func2 (6 handlers)
[GIN-debug] POST /student/add --> main.main.func3 (6 handlers)
数据库连接中........
查找数据库.......
数据正确 用户存在的
[GIN-debug] GET /authtest/test --> main.main.func4 (4 handlers)
[GIN-debug] GET /mytest/test --> main.main.func5 (4 handlers)
[GIN-debug] GET /mytest --> main.main.func6 (3 handlers)
[GIN-debug] Listening and serving HTTP on :8922
*/
// 测试例子
fmt.Println("数据库连接中........")
fmt.Println("查找数据库.......")
fmt.Println("数据正确 用户存在的")
/*
*/
return func(c *gin.Context) {
if check {
fmt.Println("需要校验")
fmt.Println("开始校验-------------")
// 存放具体的逻辑
// 是否登录的判断 。。。。
fmt.Println("校验结束-------------")
} else {
c.Next()
}
}
}
func main() {
r := gin.Default()
//r.Use(Mytestmi) // 全局的中间件 如果想全局设置的话。
r.GET("/index", Mytestmi, Myhandlerfun)
// 可以给某个路由 直接添加 写好的中间件,自行添加和去掉,对比输出 结果
// 缺点:加入路由比较多,自己每一个都要加一下, 解决方法: 直接给整体加一个,使用方法: use 函数。
r.GET("/home", Mytestmi, func(c *gin.Context) {
time.Sleep(5) // 让程序睡一会 模拟耗时的函数处理
c.JSON(http.StatusOK, gin.H{
"home": "shanxi",
"weather": "good",
})
/*
没有加中间件的执行日志信息:
日志信息
[GIN-debug] Listening and serving HTTP on :7777
[GIN] 2021/02/26 - 15:29:27 |?[97;42m 200 ?[0m| 994.3µs | 127.0.0.1 |?[97;44m GET ?[0m "/home"
[GIN] 2021/02/26 - 15:29:35 |?[97;42m 200 ?[0m| 6.9904ms | 127.0.0.1 |?[97;44m GET ?[0m "/home"
输出:
{
"home": "shanxi",
"weather": "good"
}
加了中间件之后,再次执行的日志信息
[GIN] 2021/02/26 - 15:32:09 |?[97;42m 200 ?[0m| 9.9996ms | 127.0.0.1 |?[97;44m GET ?[0m "/home"
---------------this is for middleware test----------
处理函数消耗的时间是1.0001ms
中间件函数 Mytestmi 退出
*/
})
// 创建一个路由分组 进行整体的中间件的使用
studentGroup := r.Group("/student")
// studentGroup 分组整体 使用中间件
studentGroup.Use(Mytestmi,m2,m3) // 再添加一个中间件
// 分组路由1
studentGroup.GET("/info", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"school": "深圳大学",
"Class": "三年级",
"Number": 100,
})
})
studentGroup.POST("/add", func(c *gin.Context) {
fmt.Println("路由函数 开始.....")
//实例化 一个学生结构体
stu := &Student{}
// 请求json数据绑定到 结构体
err := c.ShouldBindJSON(&stu)
if err != nil {
c.JSON(http.StatusInternalServerError,gin.H{
"err": err.Error(),
})
} else {
c.JSON(http.StatusOK,gin.H{
"result":"ok",
"message":"add successful",
"Name":stu.Name,
"Country":stu.Country,
"City":stu.City,
})
}
fmt.Println("路由函数 结束.....")
})
// AuthorCheckMiddle 测试
authtest := r.Group("/authtest")
authtest.Use(AuthorCheckMiddle(false)) // true 需要校验 false 不需要校验 可以看到输出的变化,打开是有校验的打印信息,关闭是没有走校验
authtest.GET("/test", func(c *gin.Context) {
c.JSON(http.StatusOK,gin.H{
"auth":"ok",
})
})
/*
加中间件之前
日志没有显示 中间件的信息。
[GIN-debug] Listening and serving HTTP on :8922
[GIN] 2021/02/26 - 16:02:28 |?[97;42m 200 ?[0m| 0s | 127.0.0.1 |?[97;44m GET ?[0m "/student/info"
[GIN] 2021/02/26 - 16:02:41 |?[97;42m 200 ?[0m| 0s | 127.0.0.1 |?[97;44m GET ?[0m "/student/info"
[GIN] 2021/02/26 - 16:02:42 |?[97;42m 200 ?[0m| 0s | 127.0.0.1 |?[97;44m GET ?[0m "/student/info"
[GIN] 2021/02/26 - 16:03:34 |?[90;43m 404 ?[0m| 0s | 127.0.0.1 |?[97;46m POST ?[0m "/student/info"
[GIN] 2021/02/26 - 16:03:46 |?[97;41m 500 ?[0m| 0s | 127.0.0.1 |?[97;46m POST ?[0m "/student/add"
[GIN] 2021/02/26 - 16:04:40 |?[97;42m 200 ?[0m| 0s | 127.0.0.1 |?[97;46m POST ?[0m "/student/add"
[GIN] 2021/02/26 - 16:04:46 |?[97;42m 200 ?[0m| 0s | 127.0.0.1 |?[97;46m POST ?[0m "/student/add"
输出:
http://127.0.0.1:8922/student/info get 请求
{
"Class": "三年级",
"Number": 100,
"school": "深圳大学"
}
http://127.0.0.1:8922/student/add post 请求
{
"City": "shenzhen",
"Country": "china",
"Name": "stefan",
"message": "add successful",
"result": "ok"
}
studentGroup.Use(Mytestmi) 使用中间件之后 请求日志:
[GIN-debug] Listening and serving HTTP on :8922
---------------this is for middleware test----------
处理函数消耗的时间是995.7µs
中间件函数 Mytestmi 退出
[GIN] 2021/02/26 - 16:09:14 |?[97;42m 200 ?[0m| 2.9967ms | 127.0.0.1 |?[97;44m GET ?[0m "/student/info"
---------------this is for middleware test----------
处理函数消耗的时间是0s
中间件函数 Mytestmi 退出
[GIN] 2021/02/26 - 16:09:34 |?[97;42m 200 ?[0m| 27.0001ms | 127.0.0.1 |?[97;46m POST ?[0m "/student/add"
通过日志可以看出 学生分组路由已经添加了 中间件的函数。
*/
//如果想要设置全局的中间件,就直接给 r 设置即可
/*
r := gin.Default()
r.Use(Mytestmi) use 函数中,中间件 只需要传入函数名字即可,不需要后面的括号
*/
testgroup := r.Group("/mytest")
testgroup.Use(Mytestmi,m2,m3)
testgroup.GET("/test", func(c *gin.Context) {
name,ok := c.Get("hostname") // "name" 测试 就是 匿名用户
if ! ok {
name = "匿名用户"
} else {
c.JSON(http.StatusOK,gin.H{
"hostname":name,
})
}
})
r.GET("/mytest", func(c *gin.Context) {
c.JSON(http.StatusOK,gin.H{
"message":"ok",
})
})
r.Run(":8922")
}
/*
请求日志
[GIN] 2021/02/26 - 15:20:13 |?[97;42m 200 ?[0m| 2.9978ms | 127.0.0.1 |?[97;44m GET ?[0m "/index"
---------------this is for middleware test----------
处理函数消耗的时间是998.1µs
中间件函数 Mytestmi 退出
[GIN] 2021/02/26 - 15:22:27 |?[97;42m 200 ?[0m| 998.1µs | 127.0.0.1 |?[97;44m GET ?[0m "/index"
*/
/*
添加两个中间件,观察 执行的顺序
日志输出:
[GIN-debug] Listening and serving HTTP on :8922
m1 start.....
---------------this is for middleware test----------
m2 start.....
--------------m2 test--------------
m2 stop.....
路由函数 开始.....
路由函数 结束.....
处理函数消耗的时间是2.9738ms
中间件函数 Mytestmi 退出
m1 stop.....
执行顺序: 最开始的 进入中间件1--------中间件2.... 中间件3--------- 路由函数------再到中间件1 内部处理 最后中间件1 退出
*/
执行流程图
![]()
中间件和处理函数的执行流程
[GIN-debug] Listening and serving HTTP on :8922
m1 start.....
---------------this is for middleware test----------
m2 start.....
--------------m2 test--------------
m2 stop.....
路由函数 开始.....
路由函数 结束.....
处理函数消耗的时间是2.9738ms
中间件函数 Mytestmi 退出
m1 stop.....
执行顺序: 最开始的 进入中间件1--------中间件2.... 中间件3--------- 路由函数------再到中间件1 内部处理 最后中间件1 退出