golang echo web框架中间件的实现
程序员文章站
2022-07-03 23:20:08
...
使用echo框架可以方便的定义自己的中间件,这里研究下echo中间件的实现以及是如何实现链式调用的。
比如我们有下面的中间件:
func CalHandleTime(next echo.HandlerFunc) echo.HandlerFunc {
return func(c echo.Context) (err error) {
start := time.Now()
defer func() {
fmt.Println("请求处理时间:", time.Since(start) / time.MilliSecond)
}
err = next(c)
return
}
}
func main() {
e := echo.New()
e.Use(CalHandleTime)
...
}
该中间件计算了请求处理时间,CalHandleTime仅仅返回的是一个echo.HandlerFunc方法,此时HandlerFunc方法中的代码并没有被执行。
HandlerFunc的定义如下:
HandlerFunc func(Context) error
中间件方法(MiddlewareFunc)的定义就是传入一个HandlerFunc,然后返回一个HandlerFunc:
MiddlewareFunc func(HandlerFunc) HandlerFunc
可以看下e.Use()的实现,就是把我们的中间件方法添加到中间件数组中,供后续调用:
func (e *Echo) Use(middleware ...MiddlewareFunc) {
e.middleware = append(e.middleware, middleware...)
}
我们定义自己的路由,然后使用这个中间件:
func main() {
e := echo.New()
e.GET("/hello", func(ctx echo.Context) error {
return ctx.String(http.StatusOK, "hello world~!")
}, CalHandleTime)
}
我们定义了一个Get方法的路由,Get方法第二个参数是具体的处理方法,我们简单返回hello world,这个处理方法也是一个echo.HandlerFunc,可以发现是跟中间件返回的方法类型是一致的。Get方法后面的参数都是中间件参数,执行顺序跟传入顺序一样。
我们可以看下Get方法的实现:
func (e *Echo) add(method, path string, handler HandlerFunc, middleware ...MiddlewareFunc) {
name := handlerName(handler)
e.router.Add(method, path, func(c Context) error {
h := handler
// 中间件调用链,这里串联起来了,合并成了一个方法。
for i := len(middleware) - 1; i >= 0; i-- {
h = middleware[i](h)
}
return h(c)
})
r := &Route{
Method: method,
Path: path,
Handler: name,
}
e.router.routes[method+path] = r
}
我们主要看中间件部分的实现:
e.router.Add(method, path, func(c Context) error {
h := handler
// 中间件调用链,这里串联起来了,合并成了一个方法。
for i := len(middleware) - 1; i >= 0; i-- {
h = middleware[i](h)
}
return h(c)
})
- handler是我们传入的处理业务的方法,就是返回hello world的那段代码,是echo.HandlerFunc类型,middleware是我们传入的中间件方法,可能有多个,所以这里遍历所有的,然后关联起来,并且要保证顺序。
- middleware类型是echo.MiddlewareFunc,可以看之前的定义,echo.MiddlewareFunc入参出参也都是echo.HandleFunc,跟我们处理业务逻辑的方法是一个类型,所以可以将业务处理方法和多个中间件方法返回的echo.HandlerFunc合并成一个方法。
- 可以看到中间件方法入参是(next echo.HandlerFunc),也就是下一个echo.HandlerFunc,然后返回一个新的echo.HandlerFunc方法,新的方法封装了自己的逻辑,然后再调用next echo.HandlerFunc,所以最后调用的中间件方法,里面返回的echo.HandlerFunc会先执行。
- 可以看到遍历中间件时采用了逆序的遍历,也是因为这个原因,这样可以保证第一个定义的中间件方法中的echo.HandlerFunc会先执行,然后按照中间件定义的顺序依次执行,最后执行我们的业务处理方法。这样就合并成了一个方法,当请求到来时,会执行这个方法。
如果有表意不清或者错误的地方,请联系我纠正,谢谢。
上一篇: GO web中简单的表单应用
下一篇: 如何编写Python Web框架(二)