中间件
Gin 框架允许开发者在处理请求的过程中,加入用户自己的钩子(Hook)函数。这个钩子函数就叫中间件,中间件适合处理一些公共的业务逻辑,比如登录认证、权限校验、数据分页、记录日志、耗时统计等。
通俗的讲:中间件就是匹配路由前和匹配路由完成后执行的一系列操作
路由中间件
Gin 中的中间件必须是一个 gin.HandlerFunc 类型,配置路由的时候可以传递多个 func 回调函数,最后一个 func 回调函数前面触发的方法都可以称为中间件
// 请求方式的源码参数,... 可以传入多个func(context *gin.Context)
// 可以在func(context *gin.Context)之前传入自定义的一些处理方法
(relativePath string, handlers ...HandlerFunc)
定义和使用路由中间件
写法一
// 定义一个中间件要执行的方法
func MiddlewareFunc() {
fmt.Println("中间件方法")
}
func ApiRoutersInit(router *gin.Engine) {
apiRouter := router.Group("api")
{
apiRouter.GET("list",
func(context *gin.Context) {
// 请求前执行中间件方法
MiddlewareFunc()
},
// 执行请求
func(context *gin.Context) {
context.String(http.StatusOK, "ok")
})
}
}
写法二
// 定义一个中间件要执行的方法
func MiddlewareFunc(context *gin.Context) {
fmt.Println("中间件方法")
}
func ApiRoutersInit(router *gin.Engine) {
apiRouter := router.Group("api")
{
// 写法二
apiRouter.GET("list", MiddlewareFunc,func(context *gin.Context) {
context.String(http.StatusOK, "ok")
})
}
}
ctx.Next()
中间件里面加上 ctx.Next()可以让我们在路由匹配完成后执行一些操作
func MiddlewareFunc(context *gin.Context) {
fmt.Println("请求执行前")
// 调用该请求的剩余处理程序
context.Next()
// 执行后面的func(context *gin.Context)方法
// 每调用一次 context.Next() ,向后执行一个func(context *gin.Context)
// 执行完之后再执行打印
fmt.Println("请求执行完成")
}
ctx.Abort
Abort 是终止的意思, ctx.Abort() 表示终止调用该请求的剩余处理程序
func MiddlewareFunc(context *gin.Context) {
fmt.Println("aaa")
// 终止该请求的剩余处理程序
context.Abort()
fmt.Println("这里继续打印")
}
全局中间件
func main() {
router := gin.Default()
// 在匹配路由之前配置全局中间件
// 使用Use配置全局中间件,参数就是中间件方法,可以传入多个,
router.Use(MiddlewareFunc1,MiddlewareFunc2)
router.GET("/", func(context *gin.Context) {
context.String(http.StatusOK, "ok")
})
// 将默认引擎传给其他文件定义的接收引擎的方法
api.ApiRoutersInit(router)
router.Run()
}
路由分组中间件
方法一
func ApiRoutersInit(router *gin.Engine) {
// 在路由分组的Group后配置中间件
apiRouter := router.Group("api",MiddlewareFunc)
{
apiRouter.GET("list",
// 执行请求
func(context *gin.Context) {
context.String(http.StatusOK, "ok")
})
}
}
方法二
func ApiRoutersInit(router *gin.Engine) {
apiRouter := router.Group("api")
// 调用group对象 配置中间件
apiRouter.Use(MiddlewareFunc)
{
apiRouter.GET("list",
// 执行请求
func(context *gin.Context) {
context.String(http.StatusOK, "ok")
})
}
}
中间件和对应控制器共享数据
// 中间件
func MiddlewareFunc(context *gin.Context) {
// 通过Set设置一个数据 k,v
context.Set("name", "li")
}
// 控制器
func (a ApiController) ApiSetInfo(context *gin.Context) {
// 通过.Get(key) 获取值,获取到的是一个any类型的值和是否异常的bool
username, _ := context.Get("name")
// 通过类型断言获取string类型的name
name, _ := username.(string)
context.String(http.StatusOK, name)
}
中间件注意事项
gin默认中间件
gin.Default()默认使用了 Logger 和 Recovery 中间件,其中:
• Logger 中间件将日志写入 gin.DefaultWriter,即使配置了 GIN_MODE=release。
• Recovery 中间件会 recover 任何 panic。如果有 panic 的话,会写入 500 响应码。
如果不想使用上面两个默认的中间件,可以使用 gin.New()新建一个没有任何默认中间件的路由
中间件中使用协程
当在中间件或 handler 中启动新的 goroutine 时,不能使用原始的上下文(c *gin.Context),必须使用其只读副本(c.Copy())
func MiddlewareFunc(context *gin.Context) {
c := context.Copy()
go func() {
fmt.Println("url是", c.Request.URL)
}()
go func() {
fmt.Println("body是", c.Request.Body)
}()
}
// 不需要wait等待协程完成,因为主程序main.go会一直执行
model
如果我们的应用非常简单的话,我们可以在 Controller 里面处理常见的业务逻辑。但是如果我们有一个功能想在多个控制器、或者多个模板里面复用的话,那么我们就可以把公共的功能单独抽取出来作为一个模块(Model)。 Model 是逐步抽象的过程,一般我们会在 Model里面封装一些公共的方法让不同 Controller 使用,也可以在 Model 中实现和数据库的交互
自定义一个models包,把通用的一些功能抽离来封装好,供其他地方调用,简单说models的概念就是封装一些公共方法
/*
*/
package models
import "time"
// 将时间戳转换为日期
func UnixToTime(timestamp int) string {
t := time.Unix(int64(timestamp), 0)
return t.Format("2006-01-02 15:04:05")
}
评论区