golang http 中介軟體
golang的http中介軟體的實現 首先實現一個http的handler介面
type Handler interface {
ServeHTTP(ResponseWriter, *Request)
}
type Router struct {
route map[string]Handle
}
func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
}
通過函式包裹的方式實現
中介軟體v1.0
1.通過匿名函式 將handler包裹起來 然後再 呼叫傳進來的handler。在執行傳進來的引數之前
就可以做到記錄日誌 等一些中介軟體的功能
2.如果有多箇中介軟體 那麼就多個函式 一層一層包裹
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")
})
中介軟體v1.1
註冊的時候 可以更加簡化一些 通過匿名函式的方式 當然這種方式沒有傳遞引數
只是作為演示用的
func (r *Router) Register(route string, f HandlerFunc) {
r.route[route] = withMiddLog(withMiddTime(func(writer http.ResponseWriter, request *http.Request) {
f()
}))
}
中介軟體v2.0
針對中介軟體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"))
})
golang框架gin中的實現
中介軟體v3.0
核心理念是將中介軟體和最後的函式 一視同仁 。通過一個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()
})
}