原创做者,公众号【程序员读书】,欢迎关注公众号,转载文章请注明出处哦。程序员
在今天这篇文章中,咱们来谈谈Gin框架中间件(middleware
)的使用,应该说Gin的中间件是Gin框架中一个很是重要的内容,并且Gin中间件也是使用Gin框架开发一个完整Web程序时不可或缺的部分,因此有必要好了解一下。json
Gin中间件是什么?Gin中间件的做用是什么?要怎么样使用中间件呢?bash
好吧,简单来讲,Gin中间件的做用有两个:markdown
Web请求到到达咱们定义的HTTP请求处理方法以前,拦截请求并进行相应处理(好比:权限验证,数据过滤等),这个能够类比为前置拦截器
或前置过滤器
,框架
在咱们处理完成请求并响应客户端时,拦截响应并进行相应的处理(好比:添加统一响应部头或数据格式等),这能够类型为后置拦截器
或后置过滤器
。函数
在Gin框架中,中间件的类型定义以下代码所示,能够看出,中间件实际上就是一个以gin.Context为形参的函数而已,与咱们定义处理HTTP请求的Handler本质上是同样的,并无什么神秘可言。学习
type HandlerFunc func(*Context) 复制代码
在使用Gin框架开发Web应用时,经常须要自定义中间件,不过,Gin也内置一些中间件,咱们能够直接使用,下面是内置中间件列表:spa
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 //将http.HandlerFunc包装成中间件
func WrapH(h http.Handler) HandlerFunc //将http.Handler包装成中间件
复制代码
使用gin.Default()
返回的gin.Engine
时,已经默认使用了Recovery
和Logger
中间件,从下面gin.Default()
方法的源码能够看出:debug
func Default() *Engine { debugPrintWARNINGDefault() engine := New() engine.Use(Logger(), Recovery())//使用Recovery和Logger中间 return engine } 复制代码
当咱们不想使用这两个中间件时,能够使用gin.New()方法返回一个不带中间件的gin.Engine对象:日志
router := gin.New()//不带中间件
复制代码
直拉使用gin.Engine
结构体的Use()
方法即可以在全部请求应用中间件,这样作,中间件便会在全局起做用。
router := gin.New()
router.Use(gin.Recovery())//在全局使用内置中间件
复制代码
更多的时候,咱们会根据业务不一样划分不一样路由分组(RouterGroup )
,不一样的路由分组再应用不一样的中间件,这样就达到了不一样的请求由不一样的中间件进行拦截处理。
router := gin.New() user := router.Group("user", gin.Logger(),gin.Recovery()) { user.GET("info", func(context *gin.Context) { }) user.GET("article", func(context *gin.Context) { }) } 复制代码
除了路由分组,单个请求路由,也能够应用中间件,以下:
router := gin.New() router.GET("/test",gin.Recovery(),func(c *gin.Context){ c.JSON(200,"test") }) 复制代码
也能够在单个路由中使用多个中间件,以下:
router := gin.New() router.GET("/test",gin.Recovery(),gin.Logger(),func(c *gin.Context){ c.JSON(200,"test") }) 复制代码
上面的讲解中,咱们看到,虽然Gin提供了一些中间件,咱们直接使用便可,但内置中间件可能知足不咱们业务开发的需求,在开发过程当中咱们须要开本身的中间件,这在Gin框架中是很是简单的一件事。
在前面,咱们看到Gin框架自带的中间件方法,都是返回HandlerFunc
类型,其定义以下:
type HandlerFunc func(*Context) 复制代码
HandlerFunc规范了Gin中间件的定义,因此自定义中间件,以下:
//定义中间件
func MyMiddleware(c *gin.Context){
//中间件逻辑
}
复制代码
定义好中间件,即可使用中间件,这里演示的是全局使用,也能够在单个路由或路由分组中使用:
router = gin.Default()
router.Use(MyMiddleware)
复制代码
或者,经过自定义方法,返回一个中间件函数,这是Gin框架中更经常使用的方式:
//定义一个返回中间件的方法 func MyMiddleware(){ //自定义逻辑 //返回中间件 return func(c *gin.Context){ //中间件逻辑 } } 复制代码
使用自定义的中间件,注意MyMiddleware方法后面有加括号:
router = gin.Default()
router.Use(MyMiddleware())
复制代码
当咱们在中间件拦截并预先处理好数据以后,要如何将数据传递咱们定义的处理请求的HTTP方法呢?能够使用gin.Context
中的Set()
方法,其定义以下,Set()
经过一个key来存储做何类型的数据,方便下一层处理方法获取。
func (c *Context) Set(key string, value interface{})
复制代码
当咱们在中间件中经过Set方法设置一些数值,在下一层中间件或HTTP请求处理方法中,能够使用下面列出的方法经过key获取对应数据。
其中,gin.Context的Get方法返回interface{}
,经过返回exists能够判断key是否存在。
func (c *Context) Get(key string) (value interface{}, exists bool)
复制代码
当咱们肯定经过Set方法设置对应数据类型的值时,能够使用下面方法获取应数据类型的值。
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) 复制代码
示例代码:
//自定义中间件 func MyMiddleware(c *gin.Context){ c.Set("mykey",10) } router := gin.New() router.GET("test",MyMiddleware,func(c *gin.Context){ c.GetInt("mykey")//咱们知道设置进行的是整型,因此使用GetInt方法来获取 }) 复制代码
咱们说过,中间件的最大做用就是拦截过滤请求,好比咱们有些请求须要用户登陆或者须要特定权限才能访问,这时候即可以中间件中作过滤拦截,当用户请求不合法时,能够使用下面列出的gin.Context
的几个方法中断用户请求:
下面三个方法中断请求后,直接返回200,但响应的body中不会有数据。
func (c *Context) Abort()
func (c *Context) AbortWithError(code int, err error) *Error
func (c *Context) AbortWithStatus(code int)
复制代码
使用AbortWithStatusJSON()方法,中断用户请求后,则能够返回json格式的数据.
func (c *Context) AbortWithStatusJSON(code int, jsonObj interface{})
复制代码
前面咱们讲的都是到达咱们定义的HTTP处理方法前进行拦截,其实,若是在中间件中调用gin.Context
的Next()
方法,则能够请求到达并完成业务处理后,再通过中间件后置拦截处理,Next()
方法定义以下:。
func (c *Context) Next()
复制代码
在中间件调用Next()
方法,Next()
方法以前的代码会在到达请求方法前执行,Next()
方法以后的代码则在请求方法处理后执行:
func MyMiddleware(c *gin.Context){
//请求前
c.Next()
//请求后
}
复制代码
示例代码
func MyMiddleware(c *gin.Context){ c.Set("key",1000)//请求前 c.Next() c.JSON(http.StatusOK,c.GetInt("key"))//请求后 } router := gin.New() router.GET("test", MyMiddleware, func(c *gin.Context) { k := c.GetInt("key") c.Set("key", k+2000) }) router.Run() 复制代码
上面示例程序运行结果为3000,经过上面这样一个简单的示例程序,咱们能够看到中间件在请求拦截请求,处理数据并控制Web请求流程的做用。
学习Gin框架,中间件middleware
很是重要的一块知识,它能够咱们定义处理HTTP请求的方法前拦截不合法的HTTP请求,或者预先处理好数据,或响应时添加统一的响应头部,所以在使用Gin开发Web应用时,中间件是必用的知识。
你的关注,是我写做路上最大的鼓励!