概述
我们可以先看一下HTTP Server的处理逻辑:
在这个逻辑处理的环节中,Negroni充当一个HTTP Handler的角色,并对于所有的HTTP Request的处理都会通过Negroni被转交到其内部的子中间件
实现Negroni
Negroni本质上可以被看作一个中间件是因为它实现了HTTP Handler接口,因此它可以被http.ListenAndServe()
调用:
func (n *Negroni) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
n.middleware.ServeHTTP(NewResponseWriter(rw), r)
}
而Negroni本身内部也具有自身的中间件,也就是标准库http调用中间件Negroni,然后Negroni调用自身的中间件来完成对各种HTTP Request的处理
这样设计的好处在于:对于HTTP Request来说,相当与有了一个统一的接口,所有的对HTTP Request的处理都会被转交到Negroni内部的子中间件进行处理,这样子Negroni相当与一个集线器的作用
子中间件的接口为:
type Handler interface {
ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc)
}
type HandlerFunc func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc)
Negroni自身的Handler定义与标准库http的定义非常相似,只是多了一个参数next
,这个参数使得Negroni的中间件形成链状结构
Negroni中间件链
上述我们提到Negroni对于HTTP Handler的实现的区别只在于多了一个参数next
,这是因为Negroni内部会维护一条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")))
}
其中build函数会递归创建一个类似链表结构的Handler链,结构如下:
初始化Negroni
我们可以调用Negroni.Classic()
函数来创建一个Negroni指针:
func Classic() *Negroni {
return New(NewRecovery(), NewLogger(), NewStatic(http.Dir("public")))
}
然后Classic()
函数会调用New
函数来创建并初始化一个Negroni对象并将指针返回:
func New(handlers ...Handler) *Negroni {
return &Negroni{
handlers: handlers,
middleware: build(handlers),
}
}
在New
函数中,会将传入的handlers保存下来并传给build
方法,然后build
方法会按照上面所说的方式来构建一条Handler链
Negroni.UseHandler实现
我们可以用Negroni.UseHandler来实现我们自定义的Handler,源码如下:
func (n *Negroni) UseHandler(handler http.Handler) {
n.Use(Wrap(handler))
}
方式是将传入的Handler进行一定的包装然后交给Use
函数处理:
func (n *Negroni) Use(handler Handler) {
if handler == nil {
panic("handler cannot be nil")
}
n.handlers = append(n.handlers, handler)
n.middleware = build(n.handlers)
}
然后Use
函数再将包装过的Handler加在Handler链的末尾和放到一个数组中保存
其中包装函数Wrap
的实现为:
func Wrap(handler http.Handler) Handler {
return HandlerFunc(func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
handler.ServeHTTP(rw, r)
next(rw, r)
})
}
因此UseHandler
函数本质上是将http.Handler
转换为negroni.handler
的过程
Negroni.Run实现
使用Negroni.Run函数可以运行我们的服务器,其源码为:
func (n *Negroni) Run(addr ...string) {
l := log.New(os.Stdout, "[negroni] ", 0)
finalAddr := detectAddress(addr...)
l.Printf("listening on %s", finalAddr)
l.Fatal(http.ListenAndServe(finalAddr, n))
}
在上文中也已经说过,Negroni本身也是一个Handler,因此可以直接被http.ListenAndServe
调用:
func (n *Negroni) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
n.middleware.ServeHTTP(NewResponseWriter(rw), r)
}
当http.ListenAndServe
调用Negroni.ServeHTTP接口方法时,其实是调用中间件的Handler实现的ServeHTTP接口方法:
func (m middleware) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
m.handler.ServeHTTP(rw, r, m.next.ServeHTTP)
}
因此Negroni的作用相当与一个集线器或者说Controller,将多个Handler统筹起来,让它们对于http.ListenAndServe
有一个统一的接口