Gin框架是一种用于构建Web应用程序的Go语言框架。中间件是Gin框架中的一个重要概念,用于在请求处理过程中添加一些额外的功能或处理逻辑。
Gin框架中的中间件可以在请求被处理之前或之后执行一些操作。通常,中间件用于处理请求的验证、日志记录、错误处理等功能。Gin框架提供了一种简单而灵活的方式来定义和使用中间件。
Gin框架的中间件原理可以简单概括为:通过函数包装器的方式,将中间件函数嵌入到请求处理链中,在请求被处理前或处理后执行一些额外的功能。
Gin框架中的中间件是一个函数,具有以下特点:
函数签名:中间件函数的签名为func(c *gin.Context)
,接受一个*gin.Context
类型参数,表示请求上下文。
执行顺序:中间件函数按照注册的顺序执行。在请求被处理前,按照注册的顺序依次执行前置中间件;在请求被处理后,按照相反的顺序执行后置中间件。
请求处理链:Gin框架维护了一个请求处理链,将注册的中间件函数依次包装成处理链中的环节。每个环节都可以在请求被处理前或处理后执行一些操作。
上下文传递:中间件函数可以访问和修改请求上下文中的数据。Gin框架使用*gin.Context
对象来表示请求上下文,中间件函数可以通过该对象来获取请求信息、设置响应信息等。
package main
import (
"20230615/routers"
"fmt"
"time"
"github.com/gin-gonic/gin"
)
// 定义一个 userinfo 表单结构体对象
type UserInfo struct {
UserName string `json:"username" form:"username"`
Password string `json:"password" form:"password"`
Age string `json:"age" form:"age"`
}
// 路由中间件 在路由中走的 initMiddleWares
func initMiddleWares(c *gin.Context) {
start := time.Now().UnixNano()
fmt.Println("init middleware----路由-中间件----1", start)
// c.Next()它在调用处理程序内部执行链中的挂起处理程序。Next只能在中间件内部使用
c.Next()
end := time.Now().UnixNano()
fmt.Println("init middleware----路由-中间件----2", end)
}
func main() {
// 定义一个路由引擎对象
router := gin.Default()
// 加载 渲染模板 全局
router.LoadHTMLGlob("*templates/**/*")
// 路由 get请求后 返回数据到模板渲染
router.GET("/", initMiddleWares, func(c *gin.Context) {
fmt.Println("------页面首页--------")
c.String(200, "message")
})
routers.LoginRouterInit(router) // init router 初始化路由包
router.Run(":8080")
}
输出的结果:
init middleware----路由-中间件----1 1687681850770421700
------页面首页--------
init middleware----路由-中间件----2 1687681850771422200
这里的就是中间件内部增加了 Next()方法挂起程序,让其继续执行。
通过ctrl+鼠标左键点击 ,可以追溯到源码内部查看,代码的其他方法;Abort()方法:Abort可防止调用挂起的处理程序。请注意,这不会停止当前处理程序。
package main
import (
"20230615/routers"
"fmt"
"time"
"github.com/gin-gonic/gin"
)
// 定义一个 userinfo 表单结构体对象
type UserInfo struct {
UserName string `json:"username" form:"username"`
Password string `json:"password" form:"password"`
Age string `json:"age" form:"age"`
}
// 路由中间件 在路由中走的 initMiddleWares
func initMiddleWares(c *gin.Context) {
start := time.Now().UnixNano()
fmt.Println("init middleware----路由-中间件----1", start)
// // c.Next()它在调用处理程序内部执行链中的挂起处理程序。Next只能在中间件内部使用
// c.Next()
// Abort可防止调用挂起的处理程序。请注意,这不会停止当前处理程序。
c.Abort()
end := time.Now().UnixNano()
fmt.Println("init middleware----路由-中间件----2", end)
}
func main() {
// 定义一个路由引擎对象
router := gin.Default()
// 加载 渲染模板 全局
router.LoadHTMLGlob("*templates/**/*")
// 路由 get请求后 返回数据到模板渲染
router.GET("/", initMiddleWares, func(c *gin.Context) {
fmt.Println("------页面首页--------")
c.String(200, "message")
})
routers.LoginRouterInit(router) // init router 初始化路由包
router.Run(":8080")
}
输出:
init middleware----路由-中间件----1 1687684669762450500
init middleware----路由-中间件----2 1687684669762450500
当然,演示的都是一些简单并且暂时,我们用到的方法,内部还有很多方法,就不一一演示了,可以自行查看方法的使用,追溯代码片段可以查看。
全局中间件代码演示:
func initMiddlewareOne(ctx *gin.Context) {
fmt.Println("-one-中间件-initMiddlewareOne--1")
// Next() 方法 调用该请求的剩余程序
ctx.Next()
fmt.Println("-one-中间件-initMiddlewareOne--2")
}
func initMiddlewareTwo(ctx *gin.Context) {
fmt.Println("-two--中间件--initMiddlewareTwo--1")
//终止调用该程序的剩余请求处理程序 abort()方法
// ctx.Abort()
ctx.Next()
fmt.Println("-two--中间件--initMiddlewareTwo--2")
}
func main() {
r := gin.Default()
r.SetFuncMap(template.FuncMap{
"UnitTime": UnitTime,
})
r.LoadHTMLGlob("*templates/**/*")
r.Static("/static", "./static")
// 通过 use() 方法全局注册中间件
// r.Use(initMiddlewareOne, initMiddlewareTwo)
r.GET("/", func(ctx *gin.Context) {
fmt.Println("这是一个首页")
ctx.HTML(http.StatusOK, "default/news.html", gin.H{
"title": "这个是一个首页",
})
// ctx.String(200, "这是一个首页")
})
// 抽离了 路由,传入了 r;这样就是注册了路由,同时简化了入口文件的大小
routers.DefaultRoutersInit(r)
// 登陆路由 抽离 下一步,给路由内部的方法抽离成一个 控制器 controllers
routers.LoginRoutersinit(r)
r.Run(":8001")
}
终端输出:
// 中间件内部都是next方法
-one-中间件-initMiddlewareOne--1
-two--中间件--initMiddlewareTwo--1
-one-中间件-initMiddlewareOne--1
-two--中间件--initMiddlewareTwo--2
-one-中间件-initMiddlewareOne--2
-two--中间件--initMiddlewareTwo--2
-one-中间件-initMiddlewareOne--2
以上就是演示就是路由中间件,在main.go 主入口文件下的使用,那么如何抽离出这个路由中间件initmiddlewares 呢?
这里如何给创建文件中间件init.go 注册到当前的路由中呢?
package middlewares
import (
"fmt"
"github.com/gin-gonic/gin"
)
// 方法想要其他包也可以引用,必须要让
func InitMiddlewares(c *gin.Context) {
url := c.Request.URL.String()
fmt.Println("路由分组--中间件---", url)
}
在路由中直接引入包/ middlewares
使用具体方法如下:
package routers
import (
"github.com/gin-gonic/gin"
"20230619/controllers/login"
"20230619/middlewares"
)
// 1. 如果我们要全局gold 使用,那么方法的首字母一定是大写
// 2. 路由内部的处理方法 进行抽离 使其成一个控制器 controller 「 首先, 」
func LoginRoutersinit(r *gin.Engine) {
loginRouters := r.Group("/login", middlewares.InitMiddlewares)
{
loginRouters.GET("/", login.LoginControllers{}.Index)
loginRouters.GET("/edit", login.LoginControllers{}.Edit)
}
}
Gin框架中间件的一些常见操作:
注册中间件:在Gin框架中,可以通过调用Use方法来注册中间件。例如,router.Use(middleware1, middleware2)。
全局中间件:通过在路由器上注册中间件,可以将其应用于所有的请求。例如,router.Use(globalMiddleware)。
备注:这里延伸一下,关于路由引擎定义的时候,有两种,一个是New()和 default()两种方式;建议使用default方式创建路由引擎(这种方式的是默认路由引擎使用 Logger 和 Rovery 中间件的)。
同时,这两个中间件使用都是不同的作用,
Logger 中间件将日志写入gin.DefaultWriter ,即,使用配置了 GIN_MODE=release。
Recovery 中间件会 recover 任何 panic。 如果有panic 的话,会写入500 状态码值。
但是,使用 new()方法创建路由引擎,是一个全新没有任何中间件的。源码中就可以看出来:
路由级别中间件:可以在每个路由的处理函数中注册中间件。例如,router.GET("/api", routeMiddleware, handleFunc)。
定义完中间件方法,直接放入路由中,并且只对这个路由生效。
组级别中间件:可以在路由组中注册中间件,以应用于该组下的所有路由。例如,apiGroup := router.Group("/api", groupMiddleware)。
上下文中间件:中间件可以访问和修改请求上下文中的数据。例如,验证用户身份并将用户信息存储在上下文中,供后续处理函数使用。
错误处理中间件:可以定义一个中间件来捕获并处理请求处理过程中的错误。例如,记录错误日志或返回特定的错误响应。
链式中间件:可以将多个中间件连接起来,形成一个中间件链。例如,router.Use(middleware1, middleware2, middleware3)。
总的来说,中间件是Gin框架中非常有用的功能,可以帮助开发人员实现各种常见的功能和处理逻辑,使代码更加模块化和可维护。
希望对你学习有所帮助!