欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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会先执行,然后按照中间件定义的顺序依次执行,最后执行我们的业务处理方法。这样就合并成了一个方法,当请求到来时,会执行这个方法。

如果有表意不清或者错误的地方,请联系我纠正,谢谢。

相关标签: 源码