前言
上一章我们实现了路由分组的逻辑.我们这一章根据路由分组来丰富框架的功能.一般来说鉴权,日志这种通用的功能我们可以抽象成中间件加在框架之中.例如针对
/admin/index /admin/*下的所有路径判断是否已经登录,针对所有的路由加操作日志.
代码实现
RouterGroup结构体修改
middleware []HandleFunc中间件handlers让Context存储handlers中间件组,用于调用index判断当前需要执行的中间件HandleFunc
type RouterGroup struct {
prefix string
middleware []HandleFunc
engine *Engine
parent *RouterGroup
}
type Context struct {
Writer http.ResponseWriter
Req *http.Request
Params map[string]string
Method string
Path string
StatusCode int
handlers []HandleFunc
index int 当前执行的handler
}
RouterGroup,Router,Context函数修改
Use添加handler进中间件中- 找到下一个中间件的HandleFunc
- 因为这里是index++开始,所以index要初始化为0
Handle将路由的handler绑定到Context中,通过Next去调用handler
func (g *RouterGroup) Use(handlers ...HandleFunc) {
g.middleware = append(g.middleware, handlers...)
}
func (c *Context) Next() {
c.index++
s := len(c.handlers)
for ; c.index < s; c.index++ {
c.handlers[c.index](c)
}
}
func (r *Router) Handle(c *Context) {
n, params := r.GetRouter(c.Method, c.Path)
if n != nil {
c.Params = params
//这里要注意因为是动态匹配要用n.patten不能用c.Path 因为Path是变化的
key := c.Method + "-" + n.patten
c.handlers = append(c.handlers, r.handlers[key])
} else {
c.handlers = append(c.handlers, func(ctx *Context) {
c.String(http.StatusNotFound, "404 page not find %s\n", c.Path)
})
}
c.Next()
}
测试
user := e.Group("/user")
{
user.GET("/info", func(ctx *Context) {
ctx.HTML(200, "用户信息")
})
v1 := user.Group("/v1")
{
v1.GET("/info", func(ctx *Context) {
ctx.HTML(http.StatusOK, "v1 版本用户信息")
})
v1.Use(func(ctx *Context) {
now := time.Now()
log.Print("time:" + now.String() + "|你正在访问的路由为:" + ctx.Path)
})
}
}
2023/10/17 11:25:14 time:2023-10-17 11:25:14.695475 +0800 CST m=+10.640291640|你正在访问的路由为:/user/v1/info
GET http://localhost:7999/user/v1/info
HTTP/1.1 200 OK
Date: Tue, 17 Oct 2023 03:25:14 GMT
Content-Length: 21
Content-Type: text/plain; charset=utf-8
v1 版本用户信息
总结
本章我们在路由分组层面实现了中间件的逻辑.