在 Go 语言里,Negroni 是一个很地道的 Web 中间件,它是一个具备微型、非嵌入式、鼓励使用原生 net/http 库特征的中间件。
Negroni 不是一个框架,它是为了方便使用 net/http 而设计的一个库而已。
Negroni 没有带路由功能,使用 Negroni 时,需要找一个适合你的路由。不过好在 Go 社区里已经有相当多可用的路由,Negroni 更喜欢和那些完全支持 net/http 库的路由搭配使用,比如搭配 Gorilla Mux 路由器
Negroni基本功能使用可以参考github详细说明
本质上来说Negroni是一个HTTP Handler,因为他实现了HTTP Handler接口,所以他可以被http.ListenAndServe使用,其次Negroni本身内部又有一套自己的Handler处理链,通过他们可以达到处理http请求的目的,这些Handler处理链中的处理器,就是一个个中间件。
Negroni实现了HTTP的Handler,对于HTTP Request来说,就有一个统一的入口,所有的对HTTP Requet的处理,都会被Negroni通过ServeHTTP方法转交给Negroni内部注册的中间件。
func (n *Negroni) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
n.middleware.ServeHTTP(NewResponseWriter(rw), r)
}
Negroni自己定义的Handler处理器和HTTP Handler非常相似,唯一不同的是多了一个next参数,这个next参数是组成中间件处理链的核心。
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)
在调用Use方法的时候,会把Negroni的Handler存在自己的handlers字段中,这是一个Slice类型字段,可以保存我们存放的Negroni Handler。同时会基于这个存放Negroni Handler的Slice构建中间件处理链middleware
type Negroni struct {
middleware middleware
handlers []Handler
}
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)
}
middleware struct有两个字段,一个是当前的Negroni Handler,一个是指向下一个middleware的指针next。有了这样一个middleware struct,就可以构建一个完美的中间件处理链了。
type middleware struct {
handler Handler
next *middleware
}
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 voidMiddleware() middleware {
return middleware{
HandlerFunc(func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {}),
&middleware{},
}
}
当handlers参数为空的时候,直接通过voidMiddleware函数返回一个空的middleware。
当handlers参数只有1个处理器的时候,构建的milldeware就没有next了,所以next是通过voidMiddleware函数获得的,然后再通过return middleware{handlers[0], &next}组成生成的middleware并返回。
最后一种情况,就是有1个以上的Negroni Handler,那就通过build函数循环递归了,从第2个Handler开始,不停的往后递归处理,所以最先被添加的Negroni Handler会被放在中间件处理链的前面,也就意味着会被优先执行。
调用了middleware.ServeHTTP方法,这就是中间件被执行的开始。middleware.ServeHTTP方法调用middleware中当前handler的ServeHTTP方法执行我们自己写的中间件处理逻辑。
func (m middleware) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
m.handler.ServeHTTP(rw, r, m.next.ServeHTTP)
}
当前的中间件被执行了,通过中间件函数中的next参数触发下一个中间件。我们在自己的中间件处理结束后,如果觉得有必要,就需要调用next函数,继续执行下一个中间件,如果我们不调用next函数,那么中间件链的处理,到这里就断了。