本节目标:
-
设计并实现 Web 框架的中间件(Middlewares)机制。
-
实现通用的
Logger
中间件,能够记录请求到响应所花费的时间,代码约50行
中间件是啥
我们的框架不可能理解所有的业务,框架只是一个空空的躯体,他有什么具体的功能,需要我们去实现
这个时候,中间件就出来了,类似于一个插件,嵌入到框架中
对中间件需要考虑两个点:
-
插入点在哪里,不能太底层了,那样逻辑会非常复杂
-
中间件的参数决定了扩展能力
中间件设计
我们对Context对象进行设计,目的是框架接收初始化Context对象后,允许用户使用自己定义的中间件做一些额外的请求。
package gee
import (
"log"
"time"
)
func Logger() HandlerFunc {
return func(c *Context) {
//start time
t := time.Now()
//process request 等待用户自己定义的Handler处理结束
c.Next()
//caculate resolution time
log.Printf("[%d] %s in %v", c.StatusCode, c.Req.RequestURI, time.Since(t))
}
}
注意我们支持设置多个中间件,一次进行调用
但是中间件应该复制在GROUP最顶层,这说明中间件需要有足够的功能通用性
中间件可以处理流程前,也可以处理流程后,而且中间件可能不止一个,所以我们要设计一个数组类型的HandlerFunc
type Context struct {
// origin objects
Writer http.ResponseWriter
Req *http.Request
// request info
Path string
Method string
Params map[string]string
// response info
StatusCode int
// middleware
handlers []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,服务端口才会有访问的时间