The Gin framework allows developers to add their own hook functions during the processing of requests. This hook function is called middleware. Middleware is suitable for processing some common business logic, such as login authentication, permission verification, data paging, logging, time-consuming statistics
Define middleware
The middleware in Gin must be a gin.HandlerFunc type
Entry case
package main
import (
"fmt"
"github.com/gin-gonic/gin"
"net/http"
)
func indexHandler(c *gin.Context) {
fmt.Println("index in ...")
c.JSON(http.StatusOK, gin.H{
"msg": "indx",
})
}
//定义一个中间件
func m1(c *gin.Context) {
fmt.Println("m1 in ....")
}
func main() {
r := gin.Default()
//GET(relativePath string, handlers ...HandlerFunc) IRoutes
r.GET("/index",m1,indexHandler)
//r.GET("/index", func(c *gin.Context) {
// c.JSON(http.StatusOK, gin.H{
// "msg": "indx",
// })
//})
r.Run(":9090")
}
[GIN-debug] Listening and serving HTTP on :9090
m1 in ....
index in ...
[GIN] 2020/04/21 - 15:21:31 |?[97;42m 200 ?[0m| 998.3µs | 127.0.0.1 |?[97;44m GET ?[0m "/index"
package main
import (
"fmt"
"github.com/gin-gonic/gin"
"net/http"
"time"
)
func indexHandler(c *gin.Context) {
fmt.Println("index in ...")
c.JSON(http.StatusOK, gin.H{
"msg": "indx",
})
}
//定义一个中间件:统计耗时
func m1(c *gin.Context) {
fmt.Println("m1 in ....")
//计时
start := time.Now()
c.Next() //调用后续的处理函数 执行indexHandler函数
//c.Abort() //阻止调用后续的处理函数
cost := time.Since(start)
fmt.Println("cost:%v\n", cost)
//输出
// m1 in ....
//index in ...
//cost:%v
// 996.8µs
}
func main() {
r := gin.Default()
//GET(relativePath string, handlers ...HandlerFunc) IRoutes
r.GET("/index",m1,indexHandler) //先执行m1函数再执行indexHandler函数
//r.GET("/index", func(c *gin.Context) {
// c.JSON(http.StatusOK, gin.H{
// "msg": "indx",
// })
//})
r.Run(":9090")
}
Register middleware
In the gin framework, you can add any number of middleware for each route.
Register for global routing
package main
import (
"fmt"
"github.com/gin-gonic/gin"
"net/http"
"time"
)
func indexHandler(c *gin.Context) {
fmt.Println("index in ...")
c.JSON(http.StatusOK, gin.H{
"msg": "indx",
})
}
//定义一个中间件:统计耗时
func m1(c *gin.Context) {
fmt.Println("m1 in ....")
//计时
start := time.Now()
c.Next() //调用后续的处理函数 执行indexHandler函数
//c.Abort() //阻止调用后续的处理函数
cost := time.Since(start)
fmt.Println("cost:%v\n", cost)
fmt.Println("m1 out")
//输出
// [GIN-debug] Listening and serving HTTP on :9090
//m1 in ....
//m2 in ....
//index in ...
//m2 out
//cost:%v
// 997.3µs
//m1 out
}
func m2(c *gin.Context) {
fmt.Println("m2 in ....")
c.Next() //调用后续的处理函数
fmt.Println("m2 out")
}
func main() {
r := gin.Default()
r.Use(m1,m2) //全局注册中间件函数m1,m2 洋葱模型 类似递归调用
//GET(relativePath string, handlers ...HandlerFunc) IRoutes
//r.GET("/index",m1,indexHandler) //先执行m1函数再执行indexHandler函数
r.GET("/index",indexHandler)
r.GET("/shop", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"msg": "index",
})
})
r.GET("/user", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"msg": "index",
})
})
r.Run(":9090")
}
package main
import (
"fmt"
"github.com/gin-gonic/gin"
"net/http"
"time"
)
func indexHandler(c *gin.Context) {
fmt.Println("index in ...")
c.JSON(http.StatusOK, gin.H{
"msg": "indx",
})
}
//定义一个中间件:统计耗时
func m1(c *gin.Context) {
fmt.Println("m1 in ....")
//计时
start := time.Now()
c.Next() //调用后续的处理函数 执行indexHandler函数
//c.Abort() //阻止调用后续的处理函数
cost := time.Since(start)
fmt.Println("cost:%v\n", cost)
fmt.Println("m1 out")
//输出
// [GIN-debug] Listening and serving HTTP on :9090
//m1 in ....
//m2 in ....
//m2 out
//cost:%v
// 997.8µs
//m1 out
}
func m2(c *gin.Context) {
fmt.Println("m2 in ....")
//c.Next() //调用后续的处理函数
c.Abort() //阻止后续调用
//return //return 立即结束m2函数
//m1 in ....
//m2 in ....
//cost:%v
// 0s
//m1 out
fmt.Println("m2 out")
}
//func authMiddleware(c *gin.Context) { //通常写成闭包
// //是否登陆的判断
// //if 是登陆用户
// //c.Next()
// //else
// //c.Abort()
//}
func authMiddleware(doCheck bool)gin.HandlerFunc { //开关注册
//连接数据库
//或着其他准备工作
return func(c *gin.Context) {
if doCheck {
//是否登陆的判断
//if 是登陆用户
//c.Next()
//else
//c.Abort()
} else {
c.Next()
}
}
}
func main() {
r := gin.Default()
r.Use(m1,m2,authMiddleware(true)) //全局注册中间件函数m1,m2 洋葱模型 类似递归调用
//GET(relativePath string, handlers ...HandlerFunc) IRoutes
//r.GET("/index",m1,indexHandler) //先执行m1函数再执行indexHandler函数
r.GET("/index",indexHandler)
r.GET("/shop", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"msg": "index",
})
})
r.GET("/user", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"msg": "index",
})
})
r.Run(":9090")
}
Register separately for a route
import (
"fmt"
"github.com/gin-gonic/gin"
"net/http"
"time"
)
//定义一个中间件:统计耗时
func m1(c *gin.Context) {
fmt.Println("m1 in ....")
//计时
start := time.Now()
c.Next() //调用后续的处理函数 执行indexHandler函数
//c.Abort() //阻止调用后续的处理函数
cost := time.Since(start)
fmt.Println("cost:%v\n", cost)
fmt.Println("m1 out")
}
func main() {
r := gin.Default()
r.GET("/user", m1, func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"msg": "index",
})
})
//m1 in ....
//cost:%v
// 0s
//m1 out
r.Run(":9090")
}
import (
"fmt"
"github.com/gin-gonic/gin"
"net/http"
"time"
)
func indexHandler(c *gin.Context) {
fmt.Println("index in ...")
c.JSON(http.StatusOK, gin.H{
"msg": "indx",
})
}
//定义一个中间件:统计耗时
func m1(c *gin.Context) {
fmt.Println("m1 in ....")
//计时
start := time.Now()
c.Next() //调用后续的处理函数 执行indexHandler函数
//c.Abort() //阻止调用后续的处理函数
cost := time.Since(start)
fmt.Println("cost:%v\n", cost)
fmt.Println("m1 out")
}
func m2(c *gin.Context) {
fmt.Println("m2 in ....")
//c.Next() //调用后续的处理函数
c.Abort() //阻止后续调用
//return //return 立即结束m2函数
//m1 in ....
//m2 in ....
//cost:%v
// 0s
//m1 out
fmt.Println("m2 out")
}
func main() {
r := gin.Default()
r.GET("/user", m1,m2, func(c *gin.Context) { //可以单独多个路由
c.JSON(http.StatusOK, gin.H{
"msg": "index",
})
})
//[GIN-debug] Listening and serving HTTP on :9090
//m1 in ....
//m2 in ....
//m2 out
//cost:%v
// 0s
//m1 out
r.Run(":9090")
}
Register middleware for routing groups
func main() {
//路由组注册中间件方法1:
xxGroup := r.Group("/xx", authMiddleware(true))
{
xxGroup.GET("/index", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"msg":"xxGroup"})
})
}
//路由组注册中间件方法2:
xx2Group := r.Group("/xx")
xx2Group.Use(authMiddleware(true))
{
xxGroup.GET("/index", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"msg":"xxGroup"})
})
}
r.Run(":9090")
}
Access values across middleware
package main
import (
"fmt"
"github.com/gin-gonic/gin"
"net/http"
"time"
)
func indexHandler(c *gin.Context) {
fmt.Println("index in ...")
name, ok := c.Get("name") //从上下文中取值,跨中间件存取值
if !ok {
name = "匿名用户"
}
c.JSON(http.StatusOK, gin.H{
"msg": name,
})
}
//定义一个中间件:统计耗时
func m1(c *gin.Context) {
fmt.Println("m1 in ....")
//计时
start := time.Now()
c.Next() //调用后续的处理函数 执行indexHandler函数
//c.Abort() //阻止调用后续的处理函数
cost := time.Since(start)
fmt.Println("cost:%v\n", cost)
fmt.Println("m1 out")
}
func m2(c *gin.Context) {
fmt.Println("m2 in ....")
c.Set("name","zisefeizhu") //在上下文中设置c的值
fmt.Println("m2 out")
}
func authMiddleware(doCheck bool)gin.HandlerFunc { //开关注册
//连接数据库
//或着其他准备工作
return func(c *gin.Context) {
if doCheck {
//是否登陆的判断
//if 是登陆用户
c.Next()
//else
//c.Abort()
} else {
c.Next()
}
}
}
func main() {
r := gin.Default()
r.Use(m1,m2,authMiddleware(true)) //全局注册中间件函数m1,m2 洋葱模型 类似递归调用
//GET(relativePath string, handlers ...HandlerFunc) IRoutes
//r.GET("/index",m1,indexHandler) //先执行m1函数再执行indexHandler函数
r.GET("/index",indexHandler)
r.Run(":9090")
}
Middleware considerations
gin.Default()
gin.Default () uses Logger and Recovery middleware by default, where Logger middleware writes logs to gin.DefaultWriter, even if GIN_MODE = release is configured. Recovery middleware will recover any panic. If there is panic, a 500 response code will be written. If you don't want to use the two default middleware above, you can use gin.New () to create a new route without any default middleware.
package main
import (
"fmt"
"github.com/gin-gonic/gin"
"net/http"
"time"
)
func indexHandler(c *gin.Context) {
fmt.Println("index in ...")
name, ok := c.Get("name") //从上下文中取值,跨中间件存取值
if !ok {
name = "匿名用户"
}
c.JSON(http.StatusOK, gin.H{
"msg": name,
})
}
//定义一个中间件:统计耗时
func m1(c *gin.Context) {
fmt.Println("m1 in ....")
//计时
start := time.Now()
c.Next() //调用后续的处理函数 执行indexHandler函数
//c.Abort() //阻止调用后续的处理函数
cost := time.Since(start)
fmt.Println("cost:%v\n", cost)
fmt.Println("m1 out")
}
func m2(c *gin.Context) {
fmt.Println("m2 in ....")
c.Set("name","zisefeizhu") //在上下文中设置c的值
fmt.Println("m2 out")
}
func authMiddleware(doCheck bool)gin.HandlerFunc { //开关注册
//连接数据库
//或着其他准备工作
return func(c *gin.Context) {
if doCheck {
//是否登陆的判断
//if 是登陆用户
c.Next()
//else
//c.Abort()
} else {
c.Next()
}
}
}
func main() {
//r := gin.Default() //默认使用Logger()和Recovery()中间件
r := gin.New()
r.Use(m1,m2,authMiddleware(true)) //全局注册中间件函数m1,m2 洋葱模型 类似递归调用
r.GET("/index",indexHandler)
r.GET("/shop", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"msg": "index",
})
})
r.GET("/user", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"msg": "index",
})
})
r.Run(":9090")
}
[GIN-debug] Listening and serving HTTP on :9090
m1 in ....
m2 in ....
m2 out
index in ...
cost:%v
1.0137ms
m1 out
Use goroutine in gin middleware
When starting a new goroutine in middleware or handler, the original context (c * gin.Context) cannot be used, and its read-only copy (c.Copy ()) must be used.
//定义一个中间件:统计耗时
func m1(c *gin.Context) {
fmt.Println("m1 in ....")
//计时
start := time.Now()
go funcXX(c.Copy()) //在funcXX中只能使用c的拷贝
c.Next() //调用后续的处理函数 执行indexHandler函数
//c.Abort() //阻止调用后续的处理函数
cost := time.Since(start)
fmt.Println("cost:%v\n", cost)
fmt.Println("m1 out")
}