美文网首页
Negroni源码解析

Negroni源码解析

作者: 唐西铭 | 来源:发表于2018-07-03 21:03 被阅读0次

    简介

    代码库地址: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

    相关文章

      网友评论

          本文标题:Negroni源码解析

          本文链接:https://www.haomeiwen.com/subject/hmojuftx.html