簡介
代碼庫地址:https://github.com/urfave/negroni
在 Go 語言里蔽莱,Negroni 是一個很地道的 Web 中間件躬拢,它是一個具備微型乒裆、非嵌入式痰催、鼓勵使用原生 net/http 庫特征的中間件涌乳。
在解析Negroni之前,先看一下正常http Server的處理邏輯:
其中Listen&Accept在net/http中實現(xiàn)姨夹,具體不在此描述纤垂。本文重點描述Handler,即Negroni的目標所在匀伏。其中handler只要實現(xiàn)以下接口即可:
// net/http/server.go
type Handler interface {
ServeHTTP(ResponseWriter, *Request)
}
簡單使用
func main() {
mux := http.NewServeMux()
mux.HandleFunc("/", func(rw http.ResponseWriter, req *http.Request) {
fmt.Fprint(rw, "test")
})
// 1. 創(chuàng)建一個negroni實例
n := negroni.Classic()
// 2. 在negroni實例中增加handler
n.UseHandler(mux)
// 3. 運行negroni實例
n.Run(":3000")
}
實現(xiàn)細節(jié)
Negroni實例本身其實只是一個http handler洒忧,只是內(nèi)部維護了一條handler鏈(中間件鏈)蝴韭。
新建實例
type Negroni struct {
middleware middleware
handlers []Handler
}
func New(handlers ...Handler) *Negroni {
return &Negroni{
handlers: handlers,
middleware: build(handlers),
}
}
// 遞歸創(chuàng)建一個類似鏈表的結(jié)構(gòu)
func build(handlers []Handler) middleware {
var next middleware
if len(handlers) == 0 {
return voidMiddleware()
} else if len(handlers) > 1 {
next = build(handlers[1:])
} else {
next = voidMiddleware()
}
return middleware{handlers[0], &next}
}
func Classic() *Negroni {
return New(NewRecovery(), NewLogger(), NewStatic(http.Dir("public")))
}
總體對應(yīng)的內(nèi)部結(jié)構(gòu)如下:
增加handler
增加handler的順序很重要够颠,決定了執(zhí)行順序
// 只是簡單地將該handler接入鏈表最后
func (n *Negroni) Use(handler Handler) {
n.handlers = append(n.handlers, handler)
n.middleware = build(n.handlers)
}
func (n *Negroni) UseFunc(handlerFunc func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc)) {
n.Use(HandlerFunc(handlerFunc))
}
func (n *Negroni) UseHandler(handler http.Handler) {
n.Use(Wrap(handler))
}
func (n *Negroni) UseHandlerFunc(handlerFunc func(rw http.ResponseWriter, r *http.Request)) {
n.UseHandler(http.HandlerFunc(handlerFunc))
}
運行
只是簡單地將自身作為Http-Server中的handler運行即可
func (n *Negroni) Run(addr string) {
l := log.New(os.Stdout, "[negroni] ", 0)
l.Printf("listening on %s", addr)
l.Fatal(http.ListenAndServe(addr, n))
}
寫在后話
對于Negroni正常的使用,將中間的handler用一個router替換榄鉴,如下: