2024年您产品必备的10大AI API推荐
使用gin搭建api后台系统之中间件开发
在之前的文章中,基本上都是使用的默认的 gin.Default()
来初始化一个引擎,之后再调用引擎的Run方法来运行一个web服务,现在如果有个需求,某些api只有管理员权限的才可以进行访问,非管理员的就很401,我们可以写一个方法,在需要授权的接口调用该方法来进行验权,但是在gin中还可以使用更加优雅的方法,中间件。
gin.Default() 是如何工作的?
我们先来看下gin.Default()
是如何工作的
func Default() *Engine {
debugPrintWARNINGDefault()
engine := New()
engine.Use(Logger(), Recovery())
return engine
}
它先使用New()
方法初始化一个引擎,然后再调用引擎的Use 方法,加载了两个「中间件」
func (engine *Engine) Use(middleware ...HandlerFunc) IRoutes {
engine.RouterGroup.Use(middleware...)
engine.rebuild404Handlers()
engine.rebuild405Handlers()
return engine
}
加载了两个gin中的中间件,Logger()与Recovery()
Logger()的源码为
func Logger() HandlerFunc {
return LoggerWithConfig(LoggerConfig{})
}
Recovery() 的源码为
func Recovery() HandlerFunc {
return RecoveryWithWriter(DefaultErrorWriter)
}
什么是中间件
中间件为一类函数,「HandlerFunc」 , 定义为 type HandlerFunc func(*Context)
也就是该函数的参数为Context
,也就是说,如果我们要自定义一个中间件函数的话,只需要返回一个参数为(*gin.Content)
的函数即可。
何为中间件?当一个请求到达gin服务的某个路由以后,gin 会根据路由中定义好的处理类来进行处理,以GET方法为例
func (group *RouterGroup) GET(relativePath string, handlers ...HandlerFunc) IRoutes {
return group.handle(http.MethodGet, relativePath, handlers)
}
handlers 为不定参数,也就是说可以有多个处理类,而这里的处理类类型也是HandlerFunc,和中间件是一样的。
可以理解为是中间件为多个处理请求的Handler,某个请求先经过一个Handler, 之后再经过第二个,第三个,最后将结果返回给调用者。
中间件函数中有以下两个方法比较重要
Next()
方法,该中间件处理以后,交由下一个中间件处理
Abort()
方法,调用完该方法以后,之后的HandlerFunc则不进行处理了
中间件的两种定义方式
中间件常用的有两种方式
package midwares
import (
"fmt"
"github.com/gin-gonic/gin"
"time"
)
//打印耗时的中间件
func Checktime() gin.HandlerFunc {
//这里可以处理一些别的逻辑
return func(c *gin.Context) {
start := time.Now()
c.Next()
spend:= time.Since(start).Microseconds()
fmt.Printf("use: %d \n", spend)
}
}
func Abort(c *gin.Context){
fmt.Println("使用了Abort中间件,不会进行之后处理")
c.JSON(200, gin.H{"msg": "no next"})
c.Abort()
}
这两种方式效果是一样的,只是在gin初始化加载的方式不同
r := gin.Default()
r.Use(midwares.Checktime()) //需要加上()
r.Use(midwares.Abort) // 不需要加上()
个人还是比较喜欢加上()的方式。
中间件的几种使用方式
中间件有两种使用方式,一种是全局的中间件,一种是局部中间件
如上面的使用r.Use(midware)
的方式是全局的,这种方式,每个路由都会走该中间件的逻辑。
局部中间件为在路由定义时使用,这种定义则只在该路由上有效.
userv1.GET("/abort", midwares.Abort, userv1_h.Abort)
上面我定义了两个中间件,Checktime
为记录下该请求所用的时间,Abort
中间件为测试c.Abort
函数功能,使用了该中间件的路由只会走到这里,不会再经过之后的路由了。
访问上面的路由地址 /abort
以下,控制台会输出
使用了Abort中间件,不会进行之后处理
use: 443
第一行输出为「Abort」 中间件的输出,第二行输出为「Checktime」中间件的输出。
http的返回为Abort中间件定义的返回,之后的HandlerFunc不再执行了。
{
msg: "no next"
}
基于中间件的授权管理
创建一个中间件,如果校验成功则继续往下走,如果不是管理员,则就不要往下走了,返回401
func CheckAdmin() gin.HandlerFunc{
return func(c *gin.Context) {
username := c.Query("user")
// 这里可以是从cookie或者 session 中判断
if username == "admin"{
c.Next()
}else{
c.JSON(401, gin.H{"msg": "No Private"})
c.Abort()
}
}
}
中间件的执行顺序
gin在初始化的时候加载了一些中间件,又定义了全局的中间件,又定义了路由的中间件,那么这些中间件的执行顺序是如何的呢?
执行的顺序为 全局中间件 > 路由组中间件 > 路由中间件。
参考文章
Gin框架入门(四)—中间件[1]
本文章转载微信公众号@序语程言