怎么理解中间件(middleware)?
做开发的特别是做后端开发的相信对中间件这个词肯定是很熟悉了,中间件的概念还是比较宽泛的,即使在后端开发领域,也有很多不同的含义。概况起来中间件可以理解为用于解耦业务和非业务代码的钩子函数或者程序。在web框架层面,程序运行到某个阶段自动执行预设的函数,运行完后再回到跳出的那个阶段继续执行原函数。
具体到 gin 框架,官方的说法是传入的HTTP请求可以由中间件链和最终操作来处理。可以理解为中间件是一种过滤路由的机制,也就是http请求来到时先经过中间件,再到具体的处理函数,传入的 HTTP 请求可以由一系列中间件和最终操作来处理,可以在中间件中实现前置和后置处理逻辑。
gin 中间件实现方法分析
1、gin 把中间件和主体函数统一定义为 handleFunc
// HandlerFunc defines the handler used by gin middleware as return value.
type HandlerFunc func(*Context)
// Use attaches a global middleware to the router. i.e. the middleware attached through Use() will be
// included in the handlers chain for every single request. Even 404, 405, static files...
// For example, this is the right place for a logger or error management middleware.
func (engine *Engine) Use(middleware ...HandlerFunc) IRoutes {
engine.RouterGroup.Use(middleware...)
engine.rebuild404Handlers()
engine.rebuild405Handlers()
return engine
}
// Handle registers a new request handle and middleware with the given path and method.
// The last handler should be the real handler, the other ones should be middleware that can and should be shared among different routes.
// See the example code in GitHub.
//
// For GET, POST, PUT, PATCH and DELETE requests the respective shortcut
// functions can be used.
//
// This function is intended for bulk loading and to allow the usage of less
// frequently used, non-standardized or custom methods (e.g. for internal
// communication with a proxy).
func (group *RouterGroup) Handle(httpMethod, relativePath string, handlers ...HandlerFunc) IRoutes {
if matched := regEnLetter.MatchString(httpMethod); !matched {
panic("http method " + httpMethod + " is not valid")
}
return group.handle(httpMethod, relativePath, handlers)
}
无论是是用 use 方法注册中间件,还是用 handle 方法注册主体函数,类型都是 HandlerFunc。
2、把所有 handleFunc 放入入一个元素类型为 handleChain 的数组
// HandlerFunc defines the handler used by gin middleware as return value.
type HandlerFunc func(*Context)
// HandlersChain defines a HandlerFunc slice.
type HandlersChain []HandlerFunc
3、从 handleChain 的第一个元素开始执行,中间使用 Next、Abort 等函数来进行流程控制
// Next should be used only inside middleware.
// It executes the pending handlers in the chain inside the calling handler.
// See example in GitHub.
func (c *Context) Next() {
c.index++
for c.index < int8(len(c.handlers)) {
c.handlers[c.index](c)
c.index++
}
}
// Abort prevents pending handlers from being called. Note that this will not stop the current handler.
// Let's say you have an authorization middleware that validates that the current request is authorized.
// If the authorization fails (ex: the password does not match), call Abort to ensure the remaining handlers
// for this request are not called.
func (c *Context) Abort() {
c.index = abortIndex
}
手动实现中间件逻辑程序
参考 gin 实现中间件逻辑的思路,手动实现一个简单的演示程序,如下
package main
import (
"fmt"
)
const maxIndex = 63
type HandlerFunc func(ctx *context)
type context struct {
HandlersChain []HandlerFunc
index int8
}
func (ctx *context) next() {
if ctx.index < maxIndex {
ctx.index++
ctx.HandlersChain[ctx.index](ctx)
}
}
func (ctx *context) abort() {
ctx.index = maxIndex
fmt.Println("abort...")
}
func (ctx *context) use(f HandlerFunc) {
ctx.HandlersChain = append(ctx.HandlersChain, f)
}
func (ctx *context) get(relativePath string, f HandlerFunc) {
ctx.HandlersChain = append(ctx.HandlersChain, f)
}
func (ctx *context) run() {
ctx.HandlersChain[0](ctx)
}
func main() {
ctx := &context{}
ctx.use(middleware1)
ctx.use(middleware2)
ctx.get("hahahah", logicFunc)
ctx.run()
}
func middleware1(ctx *context) {
fmt.Println("middleware1 begin")
//ctx.abort()
ctx.next()
fmt.Println("middleware1 end")
}
func middleware2(ctx *context) {
fmt.Println("middleware2 begin")
ctx.next()
fmt.Println("middleware2 end")
}
func logicFunc(ctx *context) {
fmt.Println("logicFunc function")
}
运行结果为
middleware1 begin
middleware2 begin
logicFunc function
middleware2 end
middleware1 end
相信这个简化版的中间件实现肯定可以帮助你理解其中的原理。