golang http 中介軟體

alin_qu發表於2019-06-26

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()
    })
}

相關文章