文章目录
一、介绍:
使用 BasicAuth 中间件: https://gin-gonic.com/zh-cn/docs/examples/using-basicauth-middleware/
在中间件中使用 Goroutine: https://gin-gonic.com/zh-cn/docs/examples/goroutines-inside-a-middleware/
1. 什么是中间件:
- 开发者自定义的钩子(Hook)函数;
- 类似python中的装饰器;
2. 中间件的作用
- 中间件适合处理一些公共的业务逻辑,比如登录认证、权限校验、数据分页、记录日志、耗时统计等;
- 需要对某一类函数进行通用的前置或者后置处理;
3. 使用场景
- 逻辑执行之前
- token等认证
- 权限校验
- 限流
- 数据过滤
- 白名单
- …
- 逻辑执行之后
- 数据过滤,比如敏感词等
- 统一的响应头等
- …
二、中间件的使用:
1. 使用中间件:
router := gin.New()
router.Use(gin.Logger())
router.Use(gin.Recovery())
注意:中间件的回调要先于用户定义的路径处理函数;
2. 中间价的使用位置说明
中间件的使用顺序绝对了什么时候执行中间件,比如有三个路由:
router := gin.Default()
router.Get("/login",xxx)
router.Get("/user_list",xxx)
router.Get("/news_list",xxx)
加入user_list和news_list需要在登陆后才可以访问,login不要登录认证就可访问,
这时候我们需要一个token认证的中间件,那这个中间件Use的位置会有影响,如下:
router := gin.Default()
router.Get("/login",xxx)
router.User(MiddleWare())
router.Get("/user_list",xxx)
router.Get("/news_list",xxx)
// Use不能放在login的前面,不然也会对login进行拦截认证
注意:Use不能放在login的前面,不然也会对login进行拦截认证
3. 中间件执行顺序示例:
func MiddlewareA() gin.HandlerFunc {
return func(ctx *gin.Context) {
fmt.Println("MiddlewareA before request")
// before request
ctx.Next()
// after request
fmt.Println("MiddlewareA after request")
}
}
func MiddlewareB() gin.HandlerFunc {
return func(ctx *gin.Context) {
fmt.Println("MiddlewareB before request")
// before request
ctx.Next()
// after request
fmt.Println("MiddlewareB after request")
}
}
三、gin内置中间件:
中间件 | 说明 |
---|---|
func BasicAuth(accounts Accounts) HandlerFunc | 权限认证 |
func BasicAuthForRealm(accounts Accounts, realm string) HandlerFunc realm | 认证分组 |
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包装成中间件 |
四、自定义中间件:
1. 自定义中间件的两种方式:
// 自定义中间件第1种定义方式
func MiddleWare1(ctx *gin.Context) {
fmt.Println("这是自定义中间件1")
}
// 自定义中间件第2种定义方式
func MiddleWare2() gin.HandlerFunc {
return func(ctx *gin.Context) {
fmt.Println("这是自定义中间件2")
}
}
router := gin.New()
router.Use(MiddleWare1) // 需要加括号
router.Use(MiddleWare2()) // 不需要加括号,当成参数
五、中间件中的Next和Abort:
1. Next:
在定义的众多中间件,会形成一条中间件链,而通过 Next 函数来对后面的中间件进行执行
特点:
- 当遇到ctx.Next()函数时 它取出所有的没被执行过的注册的函数都执⾏⼀遍,然后再回到本函数中,有点类似递归函数
- Next 函数是在请求前执行,而 Next 函数后是在请求后执行。
- 可以用在token校验,把用户id存起来供给功能性函数使用
2.Abort:
ctx.Abort()方法的作用 终止调用整个链条
比如:token认证没有通过,不能直接使用return返回,而是使用Abort来终止
3. 中间件执行顺序示例
func MiddleWare1(ctx *gin.Context) {
fmt.Println("这是自定义中间件1--开始")
ctx.Next()
fmt.Println("这是自定义中间件1--结束")
}
func MiddleWare2() gin.HandlerFunc {
return func(ctx *gin.Context) {
fmt.Println("这是自定义中间件2--开始")
if 3 < 4{ // 满足条件
ctx.Abort()
}
ctx.Next()
fmt.Println("这是自定义中间件2--结束")
}
}
func MiddleWare3(ctx *gin.Context) {
fmt.Println("这是自定义中间件3--开始")
ctx.Next()
fmt.Println("这是自定义中间件3--结束")
}
router := gin.Default()
router.Use(Middleware1,Middleware2(),Middleware3)
六、在全局、路由组、局部的使用:
1. 全局:
2. 路由组:
3.局部:
func Middle1Ware() gin.HandlerFunc{
return func(c *gin.Context) {
fmt.Println("我是自定义中间件第2种定义方式---请求之前")
//在gin上下文中定义一个变量
c.Set("example", "CustomRouterMiddle2")
//请求之前
c.Next()
//请求之后
fmt.Println("我是自定义中间件第2种定义方式---请求之后")
}
}
// 路由映射时可以传多个HandlerFunc
router := gin.Default()
router.GET("/hello",Middle1Ware(),Hello)
七、案例: 内置BaseAuth中间件:
1. BasicAuth中间件的使用:
// 局部使用中间价
chap05.GET("/basic",gin.BasicAuth(gin.Accounts{
"zs":"123456",
"ls":"123",
"ww":"1234",
}),BasicAuthTest)
// 私有数据
var map_data map[string]interface{} = map[string]interface{}{
"zs":gin.H{"age":18,"addr":"zs-xx"},
"ls":gin.H{"age":19,"addr":"ls-xx"},
"ww":gin.H{"age":20,"addr":"ww-xx"},
}
// 获取私有数据。如果没有权限则获取不到
func BasicAuthTest(ctx *gin.Context) {
user_name := ctx.Query("user_name")
data ,ok := map_data[user_name]
if ok{
ctx.JSON(http.StatusOK,gin.H{"user_name":user_name,"data":data})
}else {
ctx.JSON(http.StatusOK,gin.H{"user_name":user_name,"data":"没有权限"})
}
}
一文读懂HTTP Basic身份认证:https://juejin.im/entry/6844903586405564430
执行逻辑:
登录页面(没有中间件) --> 会设置session --> 其他路由回去session的key --> 获取对应的数据
2. WrapF: 中间件
gin.WrapF(IndexHandler)
func IndexHandler(w http.ResponseWriter, r *http.Request) {
...
}
3. WrapH和WrapF的区别
需要自己去定义struct实现这个Handler接口
type TestStruct struct {}
func (test *TestStruct) TestH(w http.ResponseWriter, r *http.Request) {
...
}