简介
代码库地址:https://github.com/urfave/negroni
在 Go 语言里,Negroni 是一个很地道的 Web 中间件,它是一个具备微型、非嵌入式、鼓励使用原生 net/http 库特征的中间件。
在解析Negroni之前,先看一下正常http Server的处理逻辑:
image.png
其中Listen&Accept在net/http中实现,具体不在此描述。本文重点描述Handler,即Negroni的目标所在。其中handler只要实现以下接口即可:
// 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. 创建一个negroni实例
n := negroni.Classic()
// 2. 在negroni实例中增加handler
n.UseHandler(mux)
// 3. 运行negroni实例
n.Run(":3000")
}
实现细节
Negroni实例本身其实只是一个http handler,只是内部维护了一条handler链(中间件链)。
新建实例
type Negroni struct {
middleware middleware
handlers []Handler
}
func New(handlers ...Handler) *Negroni {
return &Negroni{
handlers: handlers,
middleware: build(handlers),
}
}
// 递归创建一个类似链表的结构
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")))
}
总体对应的内部结构如下:
image.png
增加handler
增加handler的顺序很重要,决定了执行顺序
// 只是简单地将该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替换,如下:
image.png
网友评论