通过向添加handlers中间件,并按顺序执行,实现中间件
原理
首先在上下文中添加属性中间件链,记录当前执行到第几个中间件的属性。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| type Context struct { Writer http.ResponseWriter Request *http.Request
Path string Method string Params map[string]string
StatusCode int
handlers []HandlerFunc index int }
|
然后在Context中添加Next方法,用于执行下一个中间件
1 2 3 4 5 6 7 8 9
|
func (c *Context) Next() { c.index++ s := len(c.handlers) for ; c.index < s; c.index++ { c.handlers[c.index](c) } }
|
为什么要在Context设置中间件相关的属性?
因为Context是每个请求的上下文,每个请求都有自己的处理函数链,所以需要在Context中设置中间件相关的属性
因为在分组中,中间件才能发挥到真正的作用,所以在分组中也添加相关属性
1 2 3 4 5 6 7 8 9 10 11 12
| type routerGroup struct { prefix string middlewares []HandlerFunc parent *routerGroup engine *Engine }
func (group *routerGroup) Use(middlewares ...HandlerFunc) { group.middlewares = append(group.middlewares, middlewares...) }
|
这样,就可以给分组添加中间件啦。
在运行时,我们应该先处理分组中的中间件,然后再运行本身的调用函数,当然这些已经在上下文中实现,
我们只需要给上下文添加调用函数链,然后调用上下文即可。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| func (engine *Engine) ServeHTTP(w http.ResponseWriter, req *http.Request) { var middlewares []HandlerFunc for _, group := range engine.groups { if strings.HasPrefix(req.URL.Path, group.prefix) { middlewares = append(middlewares, group.middlewares...) } } c := newContext(w, req) c.handlers = middlewares engine.r.handle(c) }
func (r *router) handle(c *Context) { n, params := r.getRoute(c.Method, c.Path) if n != nil { c.Params = params key := c.Method + "-" + n.pattern c.handlers = append(c.handlers, r.handlers[key]) } else { c.handlers = append(c.handlers, func(context *Context) { context.String(404, "404 NOT FOUND: %s\n", context.Path) }) } c.Next() }
|
这样,我们就简单的实现了中间件。
大致就是这样的:调用路由处理函数时,将分组中的中间件添加到上下文中,然后调用上下文,执行中间件,最后执行路由处理函数。