gin中的中间件ctx.Next()和ctx.Abort和全局中间件
Gin 中间件
Gin框架允许开发者在处理请求的过程中,加入用户自己的钩子函数。
这个钩子函数就叫中间件。
中间件适合处理一些公共的业务逻辑,
比如登录认证、权限校验、数据分页、记录日志、耗时统计等。
通俗的讲:中间件就是匹配路由前和匹配路由完成后执行的一系列操作
package main
import (
"fmt"
"gin-quickstart/routers"
"github.com/gin-gonic/gin"
)
// "gin-quickstart/routers" 表示引入 routers 包(也就是引入我们创建的路由文件夹),用于注册路由
func getTime(ctx *gin.Context) {
fmt.Println("这是一个中间件1")
}
func getTime2(ctx *gin.Context) {
fmt.Println("这是一个中间件2")
}
func main() {
// 创建一个默认的路由引擎
r := gin.Default()
// 允许跨域中间件(注意:必须写在路由注册【之前】才对已注册路由生效)
r.Use(func(c *gin.Context) {
c.Header("Access-Control-Allow-Origin", "*") // 允许所有来源(学习阶段够用)
c.Header("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")
c.Header("Access-Control-Allow-Headers", "Content-Type")
// 浏览器发复杂请求前会先发 OPTIONS 预检,直接放行
if c.Request.Method == "OPTIONS" {
c.AbortWithStatus(204)
return
}
c.Next()
})
// 注册用户路由,routers表示的是路由包,
// UserRouters表示的是路由函数(也就是这个包中user.go文件中的函数)
routers.UserRouters(r)
// 注册商品路由
r.GET("/shop/list",
// 这里写了2个中间件
getTime, getTime2,
// 这个回调函数前面的都可以称为中间件
func(ctx *gin.Context) {
fmt.Println("这是商品列表页面")
ctx.JSON(200, gin.H{
"msg": "获取商品列表成功",
})
})
// 启动服务,端口为8080,当然你也可以更改的哈
r.Run(":8087")
}
执行顺序是:
这是一个中间件1
这是一个中间件2
这是商品列表页面
ctx.Next()调用该请求的剩余处理程序
中间件里面加上ctx.Next()可以让我们在路由匹配完成之后执行一些操作。
比如我们统计一个请求的执行时间。
func getTime(ctx *gin.Context) {
fmt.Println("这是一个中间件1")
ctx.Next()
fmt.Println("最后执行这里")
}
func main() {
// 其他代码...
// 注册商品路由
r.GET("/shop/list",
getTime,
// 这个回调函数前面的都可以称为中间件
func(ctx *gin.Context) {
fmt.Println("这是商品列表页面")
ctx.JSON(200, gin.H{
"msg": "获取商品列表成功",
})
})
}
执行顺序:匹配到这里路由后,会先执行中间件。
执行:fmt.Println("这是一个中间件1")
然后执行中间件后面的这一坨代码
func(ctx *gin.Context) {
fmt.Println("这是商品列表页面")
ctx.JSON(200, gin.H{
"msg": "获取商品列表成功",
})
}
当它执行完成之后,
最后才会执行:fmt.Println("最后执行这里")

ctx.Abort 终止调用该请求的剩余处理程序
func getTime(ctx *gin.Context) {
// 纳秒时间戳;统计处理完业务的耗时
startTime := time.Now().UnixNano()
fmt.Println("这是一个中间件1")
ctx.Abort()
endTime := time.Now().UnixNano()
fmt.Println("这是一个中间件2")
fmt.Println("请求耗时:", endTime-startTime)
}
func main() {
... 其他代码
// 注册商品路由
r.GET("/shop/list",
// 这里写了2个中间件
getTime,
// 这个回调函数前面的都可以称为中间件
func(ctx *gin.Context) {
fmt.Println("这是商品列表页面")
ctx.JSON(200, gin.H{
"msg": "获取商品列表成功",
})
})
// 启动服务,端口为8080,当然你也可以更改的哈
r.Run(":8087")
}
先执行:这是一个中间件1
遇见ctx.Abort(),会终止调用该请求的剩余处理程序
此时不会再去执行路由中的业务逻辑fmt.Println("这是商品列表页面")
而是执行:这是一个中间件2
执行顺序是:
15:5:35 app | 这是一个中间件1
15:5:35 app | 这是一个中间件2
请求耗时: 0

多个中间件调用ctx.Next()的执行顺序
func getTime(ctx *gin.Context) {
fmt.Println("这是一个中间件A1")
// 调用该请求的剩余处理程序
ctx.Next()
fmt.Println("这是一个中间件A2")
}
func intercept(ctx *gin.Context) {
fmt.Println("这是一个中间件B1")
// 调用该请求的剩余处理程序
ctx.Next()
fmt.Println("这是一个中间件B2")
}
func main() {
... 其他代码
// 注册商品路由
r.GET("/shop/list",
getTime, intercept,
// 这个回调函数前面的都可以称为中间件
func(ctx *gin.Context) {
fmt.Println("这是商品列表页面")
ctx.JSON(200, gin.H{
"msg": "获取商品列表成功",
})
})
// 启动服务,端口为8080,当然你也可以更改的哈
r.Run(":8087")
}
首先执行:这是一个中间件A1,遇见ctx.Next(),会调用该请求的剩余处理程序
然后执行:这是一个中间件B1,遇见ctx.Next(),会调用该请求的剩余处理程序
然后执行:这是商品列表页面
然后开始先进后出
执行:这是一个中间件B2,
最后执行:这是一个中间件A2

全局中间件 r.Use()
为啥会有全局中间件。因为一个一个的配置路由太麻烦了。
我们可以一次性给所有路由都添加一个中间件。
于是就产生了全局中间件。
func getTime(ctx *gin.Context) {
fmt.Println("这是一个中间件A1")
// 调用该请求的剩余处理程序
ctx.Next()
fmt.Println("这是一个中间件A2")
}
func intercept(ctx *gin.Context) {
fmt.Println("这是一个中间件B1")
// 调用该请求的剩余处理程序
ctx.Next()
fmt.Println("这是一个中间件B2")
}
func globalIntercept(ctx *gin.Context) {
fmt.Println("这是一个全局中间件1")
ctx.Next()
fmt.Println("这是一个全局中间件2")
}
func main() {
... 其他代码
r.Use(globalIntercept)
// 注册商品路由
r.GET("/shop/list",
getTime, intercept,
// 这个回调函数前面的都可以称为中间件
func(ctx *gin.Context) {
fmt.Println("这是商品列表页面")
ctx.JSON(200, gin.H{
"msg": "获取商品列表成功",
})
})
// 启动服务,端口为8080,当然你也可以更改的哈
r.Run(":8087")
}
执行顺序是:
这是一个全局中间件1
这是一个中间件A1
这是一个中间件B1
这是商品列表页面
这是一个中间件B2
这是一个中间件A2
这是一个全局中间件2
出处:https://www.cnblogs.com/ishoulgodo/
想问问题,打赏了卑微的博主,求求你备注一下的扣扣或者微信;这样我好联系你;(っ•̀ω•́)っ✎⁾⁾!
如果觉得这篇文章对你有小小的帮助的话,记得在右下角点个“推荐”哦,或者关注博主,在此感谢!
万水千山总是情,打赏5毛买辣条行不行,所以如果你心情还比较高兴,也是可以扫码打赏博主(っ•̀ω•́)っ✎⁾⁾!
想问问题,打赏了卑微的博主,求求你备注一下的扣扣或者微信;这样我好联系你;(っ•̀ω•́)っ✎⁾⁾!
如果文中有什么错误,欢迎指出。以免更多的人被误导。

浙公网安备 33010602011771号