本节目标:
-
设计并实现 Web 框架的中间件(Middlewares)机制。
-
实现通用的
Logger
中间件,能够记录请求到响应所花费的时间,代码约50行
中间件是啥
我们的框架不可能理解所有的业务,框架只是一个空空的躯体,他有什么具体的功能,需要我们去实现
这个时候,中间件就出来了,类似于一个插件,嵌入到框架中
对中间件需要考虑两个点:
-
插入点在哪里,不能太底层了,那样逻辑会非常复杂
-
中间件的参数决定了扩展能力
中间件设计
我们对Context对象进行设计,目的是框架接收初始化Context对象后,允许用户使用自己定义的中间件做一些额外的请求。
package geeimport ("log""time"
)func Logger() HandlerFunc {return func(c *Context) {//start timet := time.Now()//process request 等待用户自己定义的Handler处理结束c.Next()//caculate resolution timelog.Printf("[%d] %s in %v", c.StatusCode, c.Req.RequestURI, time.Since(t))}
}
注意我们支持设置多个中间件,一次进行调用
但是中间件应该复制在GROUP最顶层,这说明中间件需要有足够的功能通用性
中间件可以处理流程前,也可以处理流程后,而且中间件可能不止一个,所以我们要设计一个数组类型的HandlerFunc
type Context struct {// origin objectsWriter http.ResponseWriterReq *http.Request// request infoPath stringMethod stringParams map[string]string// response infoStatusCode int// middlewarehandlers []HandlerFunc//存储中间件index int //记录第几个中间件
}func newContext(w http.ResponseWriter, req *http.Request) *Context {return &Context{Path: req.URL.Path,Method: req.Method,Req: req,Writer: w,index: -1,}
}func (c *Context) Next() {c.index++ //s := len(c.handlers)for ; c.index < s; c.index++ {c.handlers[c.index](c)}
}
在这一章里面,大家还是要去看一下源码,感觉文章里面有些东西没写清楚,特别是测试的main部分
这里测试的话不要使用curl工具,直接在网页上面访问url,服务端口才会有访问的时间