Go 实现 Web 框架 Day4-5 学习笔记
极客兔兔大佬的《七天用Go从零实现系列》Day4 分组控制,Day5 中间件 学习笔记
Day4 -5内容
- 路由分组控制(Gropu Contorl)
- 中间件添加,请求处理前、后的功能定制
本节新的知识点
- 嵌套结构体
- strings.HasPrefix() 判定
开发内容
内容地址
开发目的:
将路由分组进行控制,在不同的组加不同的定制化功能,也可以全局定制功能。
开发步骤
- 增加 RouterGroup 作为路由分组
- 在不同的路由分组中增加 [] HandlerFunc 作为中间件
- 在原来router.handle() 中作为切点,进行中间件调用
部分实现解读
-
增强功能的函数的实现
与之前定义的请求处理函数一样,可以使用切片来统一维护,方便管理 -
全局增强函数的添加
使用嵌套结构体*RouterGroup,将它作为全局增强函数添加的依附点,且初始化 groups 切片时直接加入
//New is the constructor of gee.Engine func New() *Engine { engine := &Engine{router: newRouter()} engine.RouterGroup = &RouterGroup{engine: engine} //全局 RouterGroup engine.groups = []*RouterGroup{engine.RouterGroup} //初始化切片时直接添加到 groups 中 return engine }
ServerHTTP 方法中,根据前缀匹配到具体的RouterGroup,然后append 组装 增强函数。
func (e *Engine) ServeHTTP(w http.ResponseWriter, req *http.Request) { var middlewares []HandlerFunc for _, group := range e.groups { if strings.HasPrefix(req.URL.Path, group.prefix) {// 全局路由分组 engine.RouterGroup prefix 为空字串,永远为true middlewares = append(middlewares, group.middlewares...) } } c := newContext(w, req) c.handlers = middlewares e.router.handle(c) }
-
增强函数的触发
增强函数在Context 中被组装存储到[]HandlerFunc,且使用链式调用实现增强函数的触发。
其中 index 做为序号,初始化为 -1。在 Next 触发的时候,先 c.index++ 再调用,保证从0开始且只执行一次。func newContext(w http.ResponseWriter, req *http.Request) *Context { return &Context{ Writer: w, Req: req, Path: req.URL.Path, Method: req.Method, index: -1, //注意这里定义为-1 } } //Next 链式调用定制的 HandlerFunc func (c *Context) Next() { c.index++ // 每次 Next 都会自增 s := len(c.handlers) for ; c.index < s; c.index++ { // 最后调用完之后回去的时候, index 已经 ==len(c.handlers) c.handlers[c.index](c) } }
思考题
- 嵌套结构体是什么?
- strings.HashPrefix 实现,判定包含空字串如何实现?
- 链式调用增强前置后置函数如何实现?
最后答案单独列一篇,可以自己试着解答一下。
小结
Day4-5 主要是在前3天的基础上做一些非功能型的扩展。
先将路由进行分组,然后在不同的分组中增加需要加强的函数。
在生成Context时,根据请求拼 增强函数,最后在之前 router.handle 的地方进行链式触发。