源码连接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() }) }