源碼連接git
golang的http中間件的實現 首先實現一個http的handler接口github
type Handler interface { ServeHTTP(ResponseWriter, *Request) } type Router struct { route map[string]Handle } func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) { }
1.經過匿名函數 將handler包裹起來 而後再 調用傳進來的handler。在執行傳進來的參數以前
就能夠作到記錄日誌 等一些中間件的功能golang
2.若是有多箇中間件 那麼就多個函數 一層一層包裹app
func withMiddle(h Handle) Handle { return func(writer http.ResponseWriter, request *http.Request) { t := time.Now() defer func() { log.Println("time spend is ", time.Since(t)) }() h(writer, request) } } func (r *Router) Register1(route string, f Handle) { r.route[route] = withMiddle(f) } func (r *Router) Register2(route string, f Handle) { r.route[route] = withMiddLog(withMiddTime(f)) } Register("/bench", func(writer http.ResponseWriter, request *http.Request) { time.Sleep(time.Second) fmt.Println("bench sleep 1 second") })
註冊的時候 能夠更加簡化一些 經過匿名函數的方式 固然這種方式沒有傳遞參數
只是做爲演示用的框架
func (r *Router) Register(route string, f HandlerFunc) { r.route[route] = withMiddLog(withMiddTime(func(writer http.ResponseWriter, request *http.Request) { f() })) }
針對中間件v1.1中的無法傳遞 http中的讀寫參數的問題 能夠封裝一個context
將http的讀寫參數都包裹進來 這樣就能夠很方便的處理讀寫了函數
func (r *Server) Register(route string, f HandlerFunc) { r.route[route] = withMiddLog(withMiddTime(func(writer http.ResponseWriter, request *http.Request) { f(r.createContext(writer, request)) })) } r.Register("/bench", func(c *Context) { time.Sleep(time.Second) fmt.Println("bench sleep 1 second") c.Writer.Write([]byte("hello!\r\n")) })
核心理念是將中間件和最後的函數 一視同仁 。經過一個for循環遍歷具體的能夠參考代碼日誌
func (c *Context) Next() { c.index++ //for中的index++是爲了退出循環 不然無法退出 for ; c.index < len(c.middle); c.index++ { c.middle[c.index](c) } } func withMiddTime() HandleContext { return func(c *Context) { t := time.Now() defer func() { fmt.Println("withMiddTime end time", time.Since(t)) }() fmt.Println("withMiddTime start ", time.Since(t)) c.Next() } } func (s *Server) Register(path string, f ...HandleContext) { handleNew := make([]HandleContext, 0, len(s.handle)+len(f)) handleNew = append(handleNew, s.handle...) handleNew = append(handleNew, f...) s.routeHandler(path, func(writer http.ResponseWriter, request *http.Request) { s.createContext(writer, request, handleNew).Next() }) }