Negroni源码解析

简介

代码库地址:https://github.com/urfave/negroni

在 Go 语言里,Negroni 是一个很地道的 Web 中间件,它是一个具备微型、非嵌入式、鼓励使用原生 net/http 库特征的中间件。

在解析Negroni之前,先看一下正常http Server的处理逻辑:


Negroni源码解析_第1张图片
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")))
}

总体对应的内部结构如下:


Negroni源码解析_第2张图片
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替换,如下:


Negroni源码解析_第3张图片
image.png

你可能感兴趣的:(Negroni源码解析)