中间件的作用
在我们熟悉的一个完整的http
请求中, 客户端先向服务端发送的http request
, 服务端接收到request
之后, 根据实际需要, 给客户端返回http response
站在服务端的角度来看, 就是接收request
, 响应response
, 而中间件的作用, 就在request
与response
之间
- 收到
request
之后, 在request
还未到达处理的handler
之前, 可以通过中间件做出一系列的数据处理, 可以看做是前置校验或过滤
request
到达handler
之后, 中间件还可以根据需要对响应体做统一的数据处理
gin内置的中间件
1 2 3 4 5 6 7 8 9 10 11 12 13
| func BasicAuth(accounts Accounts) HandlerFunc func BasicAuthForRealm(accounts Accounts, realm string) HandlerFunc func Bind(val interface{}) HandlerFunc func ErrorLogger() HandlerFunc func ErrorLoggerT(typ ErrorType) HandlerFunc func Logger() HandlerFunc func LoggerWithConfig(conf LoggerConfig) HandlerFunc func LoggerWithFormatter(f LogFormatter) HandlerFunc func LoggerWithWriter(out io.Writer, notlogged ...string) HandlerFunc func Recovery() HandlerFunc func RecoveryWithWriter(out io.Writer) HandlerFunc func WrapF(f http.HandlerFunc) HandlerFunc func WrapH(h http.Handler) HandlerFunc
|
中间件的作用域
1 2
| r := gin.Default() r := gin.New()
|
全局作用域
1 2
| r := gin.New() r.Use(gin.Recovery())
|
组作用域
1 2 3 4 5 6
| r := gin.New() vm := r.Group("vm", gin.Logger(),gin.Recovery()) { vm.GET("cpu", func(context *gin.Context) {}) vm.GET("ram", func(context *gin.Context) {}) }
|
单个路由作用域
1 2 3 4
| r := gin.New() router.GET("/healthcheck",gin.Recovery(),gin.Logger(),func(c *gin.Context){ c.JSON(200,"ok") })
|
自定义中间件
1 2 3 4
| func middleware1(c *gin.Context){ }
|
1 2 3
| r := gin.Default() r.Use(middleware1)
|
注意: r.Use()
中的中间件函数没有()
1 2 3 4 5 6
| func middleware2() gin.HandlerFunc { return func(c *gin.Context) { } }
|
1 2 3
| r := gin.Default() r.Use(middleware2())
|
数据传递
gin.Context
中提供了Set``Get
函数用来存储和提取数据
1 2 3 4 5 6
| func middleware2() gin.HandlerFunc { return func(c *gin.Context) { c.Set("name", c.Request.Header.Get("name")) } }
|
1 2 3 4 5 6 7
| r.GET("/", func(c *gin.Context) { c.JSON(200, gin.H{ "name": c.Get("name"), "message": "ok", }) })
|
Set
方法存储的值为interface{}
类型, Get
方法中提供以下常用的数据类型方便提取数据
1 2 3 4 5 6 7 8 9 10 11
| func (c *Context) GetBool(key string) (b bool) func (c *Context) GetDuration(key string) (d time.Duration) func (c *Context) GetFloat64(key string) (f64 float64) func (c *Context) GetInt(key string) (i int) func (c *Context) GetInt64(key string) (i64 int64) func (c *Context) GetString(key string) (s string) func (c *Context) GetStringMap(key string) (sm map[string]interface{}) func (c *Context) GetStringMapString(key string) (sms map[string]string) func (c *Context) GetStringMapStringSlice(key string) (smss map[string][]string) func (c *Context) GetStringSlice(key string) (ss []string) func (c *Context) GetTime(key string) (t time.Time)
|
拦截request请求
1 2 3 4 5
|
func middleware1(c *gin.Context) { c.Request.Header.Set("abc", "123") }
|
1 2 3 4 5 6 7 8
| r.GET("/", func(c *gin.Context) { fmt.Println(c.Request.Header.Get("abc")) c.JSON(200, gin.H{ "message": "ok", }) })
|
1 2 3 4 5 6
| func middleware2() gin.HandlerFunc { return func(c *gin.Context) { c.Header("xyz", "789") } }
|
追加handler处理后的动作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| package main
import ( "github.com/gin-gonic/gin" )
func middleware2() gin.HandlerFunc { return func(c *gin.Context) { c.Next() c.String(200, "handler ok\n") } }
func main() { r := gin.Default() r.Use(middleware2())
r.GET("/", func(c *gin.Context) { c.String(200, "handler ok\n") })
if err := r.Run(":8080"); err != nil { panic(err) } }
|
1 2 3
| curl http://127.0.0.1:8080/ handler ok middleware ok
|
c.Next()
c.Next()
函数允许我们在中间件中控制调度的逻辑, 每执行到c.Next()
一次, 执行权就会别切换到其他中间件或handler
函数中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
| package main
import ( "fmt" "github.com/gin-gonic/gin" )
func middleware1() gin.HandlerFunc { return func(c *gin.Context) { fmt.Println("start middleware1") c.Next() fmt.Println("end middleware1") } }
func middleware2() gin.HandlerFunc { return func(c *gin.Context) { fmt.Println("start middleware2") c.Next() fmt.Println("end middleware2") } }
func middleware3() gin.HandlerFunc { return func(c *gin.Context) { fmt.Println("start middleware3") c.Next() fmt.Println("end middleware3") } }
func main() { r := gin.Default()
r.Use(middleware1(), middleware2(), middleware3())
r.GET("/", func(c *gin.Context) { fmt.Println("start handler") c.String(200, "ok\n") fmt.Println("end handler") })
if err := r.Run(":8080"); err != nil { panic(err) } }
|
运行:
访问:
1
| curl http://127.0.0.1:8080
|
程序日志:
1 2 3 4 5 6 7 8
| start middleware1 start middleware2 start middleware3 start handler end handler end middleware3 end middleware2 end middleware1
|
依据注册中间件的顺序, 每次遇到c.Next()
函数就跳转到下一个中间件执行, 直到跳转到最后一个中间件, 再次遇到c.Next()
的时候, 就跳到handler
主函数中运行, 当handler
执行完毕后, 再逐层向上返回, 继续执行c.Next()
之后的代码
c.Abord()
c.Abord()
用来终止request
, 阻止其到达handler
一般情况下用在鉴权与认证的中间件中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
| package main
import ( "fmt" "github.com/gin-gonic/gin" )
func middleware1() gin.HandlerFunc { return func(c *gin.Context) { fmt.Println("start middleware1") c.Next() fmt.Println("end middleware1") } }
func middleware2() gin.HandlerFunc { return func(c *gin.Context) { fmt.Println("start middleware2") c.Abort() fmt.Println("end middleware2") } }
func middleware3() gin.HandlerFunc { return func(c *gin.Context) { fmt.Println("start middleware3") c.Next() fmt.Println("end middleware3") } }
func main() { r := gin.Default()
r.Use(middleware1(), middleware2(), middleware3())
r.GET("/", func(c *gin.Context) { fmt.Println("start handler") c.String(200, "ok\n") fmt.Println("end handler") })
if err := r.Run(":8080"); err != nil { panic(err) } }
|
访问后, 程序日志:
1 2 3 4
| start middleware1 start middleware2 end middleware2 end middleware1
|
可以看到即使在middleware2
中执行了c.Abord()
, c.Abord()
后面的代码依然被完整的执行, 并且返回到了middleware1
跳转的地方, 继续执行了后续代码