golang echo web框架中間件的實現

使用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會先執行,然後按照中間件定義的順序依次執行,最後執行我們的業務處理方法。這樣就合併成了一個方法,當請求到來時,會執行這個方法。

如果有表意不清或者錯誤的地方,請聯繫我糾正,謝謝。

發佈了182 篇原創文章 · 獲贊 19 · 訪問量 47萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章