Negroni中间件源码分析

概述

我们可以先看一下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指针:

扫描二维码关注公众号,回复: 12682705 查看本文章
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有一个统一的接口

猜你喜欢

转载自blog.csdn.net/qq_44026293/article/details/109963973