GoFrame提供了优雅的中间件请求控制方式,该方式也是主流的WebServer提供的请求流程控制方式,基于中间件设计可以为WebServer提供更灵活强大的插件机制。经典的中间件洋葱模型:
GoFrame
WebServer
中间件的定义和普通HTTP执行方法HandlerFunc一样,但是可以在Request参数中使用Middleware属性对象来控制请求流程。
HandlerFunc
Request
Middleware
我们拿一个跨域请求的中间件定义来示例说明一下:
func MiddlewareCORS(r *ghttp.Request) { r.Response.CORSDefault() r.Middleware.Next() }
可以看到在该中间件中执行完成跨域请求处理的逻辑后,使用r.Middleware.Next()方法进一步执行下一个流程;如果这个时候直接退出不调用r.Middleware.Next()方法的话,将会退出后续的执行流程(例如可以用于请求的鉴权处理)。
r.Middleware.Next()
中间件的类型分为两种:前置中间件和后置中间件。前置即在路由服务函数调用之前调用,后置即在其后调用。
其定义类似于:
func Middleware(r *ghttp.Request) { // 中间件处理逻辑 r.Middleware.Next() }
func Middleware(r *ghttp.Request) { r.Middleware.Next() // 中间件处理逻辑 }
中间件的注册有多种方式,参考接口文档: https://pkg.go.dev/github.com/gogf/gf/v2/net/ghttp
func (s *Server) Use(handlers ...HandlerFunc)
全局中间件是可以独立使用的请求拦截方法,通过路由规则的方式进行注册,绑定到Server上,由于中间件需要执行请求拦截操作,因此往往是使用"模糊匹配"或者"命名匹配"规则。
Server
全局中间件仅对动态请求拦截有效,无法拦截静态文件请求。
func (g *RouterGroup) Middleware(handlers ...HandlerFunc) *RouterGroup
分组路由中注册的中间件绑定到当前分组路由中的所有的服务请求上,当服务请求被执行前会调用到其绑定的中间件方法。 分组路由仅有一个Middleware的中间件注册方法。分组路由中间件与全局中间件不同之处在于,分组路由中间件无法独立使用,必须在分组路由注册中使用,并且绑定到当前分组路由中所有的路由上作为路由方法的一部分。
由于全局中间件也是通过路由规则执行,那么也会存在执行优先级:
这里的建议来参考于gRPC的拦截器设计,没有过多的路由控制,仅在一个地方同一个方法统一注册。往往越简单,越容易理解,也便于长期维护。
gRPC
分组路由中间件是绑定到分组路由上的服务方法,不存在路由规则匹配,因此只会按照注册的先后顺序执行。参考后续示例。
如果在有分层的分组路由中使用中间件,同一个中间件只会执行一次,例如: