Go的Negroni库 - Go语言中文社区

Go的Negroni库


Go的Negroni库

Negroni库下载安装

go get -u github.com/urfave/negroni

Negroni库的结构

这是Negroni库的函数大致结构
Alt textNegroni结构
首先由课上老师追踪Go的web服务包说起
(此追踪流程出自http://blog.csdn.net/pmlpml/article/details/78404838

ListenAndServe(addr string, handler Handler)
  + server.ListenAndServe()
    | net.Listen("tcp", addr)
    + srv.Serve(tcpKeepAliveListener{ln.(*net.TCPListener)})
      | srv.setupHTTP2_Serve()
      | baseCtx := context.Background()
      + for {}
        | l.Accept()
        |  + select ... //为什么
        | c := srv.newConn(rw)
        | c.setState(c.rwc, StateNew) // before Serve can return
        + go c.serve(ctx) // 新的链接 goroutine
          | ...  // 构建 w , r
          | serverHandler{c.server}.ServeHTTP(w, w.req)
          | ...  // after Serve

可以看到Go的http包在serverHandler{c.server}.ServeHTTP(w, w.req) 实现每个 conn 对应一个 serverHandler 的处理函数。
而在Negroni包中则只是实现了这一接口,该库可以认为是为了方便我们实现Handler.
那么首先我们从这个接口的实现开始,在http包中存在这么一个接口

type Handler interface {
    ServeHTTP(ResponseWriter, *Request)
}

而在Negroni包中首先是该接口的实现

func (n *Negroni) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
    n.middleware.ServeHTTP(NewResponseWriter(rw), r)
}

可以看到Negroni类型将处理丢给了middleware处理,那么我们看看Negroni里的middleware以及其他成员

type Negroni struct {
    middleware middleware
    handlers   []Handler
}

可以看到有一个Handler的切片和一个middleware,对于这两者,其定义分别是

type middleware struct {
    handler Handler
    next    *middleware
}

这个定义就类似与c语言的链表结构了,可以将其理解为middleware是用来连接handler的数据结构吧
而对于Handler,其定义如下

// Handler handler is an interface that objects can implement to be registered to serve as middleware
// in the Negroni middleware stack.
// ServeHTTP should yield to the next middleware in the chain by invoking the next http.HandlerFunc
// passed in.
//
// If the Handler writes to the ResponseWriter, the next http.HandlerFunc should not be invoked.
type Handler interface {
    ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc)
}

这里Handler将http接口稍微做了拓展,这是http.HandlerFunc的定义

// The HandlerFunc type is an adapter to allow the use of
// ordinary functions as HTTP handlers. If f is a function
// with the appropriate signature, HandlerFunc(f) is a
// Handler that calls f.
type HandlerFunc func(ResponseWriter, *Request)

可以看到本质上这与我们前面说到的http包调用的接口ServeHTTP是一个类型,Negroni包定义的Handler类型只是增加了一个指向http.HandlerFunc的参数,你可以在下文看到它会将所有handler形成链状结构
在Negroni包的Handler interface下面也有一段类似的HandlerFunc

// HandlerFunc is an adapter to allow the use of ordinary functions as Negroni handlers.
// If f is a function with the appropriate signature, HandlerFunc(f) is a Handler object that calls f.
type HandlerFunc func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc)

现在我们回过头看刚刚的n.middleware.ServeHTTP(NewResponseWriter(rw), r),这里我们跟踪一下middleware.ServeHTTP

func (m middleware) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
    m.handler.ServeHTTP(rw, r, m.next.ServeHTTP)
}

可以看到它调用了自己的成员handler的ServeHTTP,那么我们看一下对应函数

// HandlerFunc is an adapter to allow the use of ordinary functions as Negroni handlers.
// If f is a function with the appropriate signature, HandlerFunc(f) is a Handler object that calls f.
type HandlerFunc func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc)

func (h HandlerFunc) ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
    h(rw, r, next)
}

可以看到它是将HandlerFunc进行执行,至此我们追踪完上面那个结构图的右边部分,那么HandlerFunc又是在哪里初始化或者传入Negroni中呢,我们先从github上给的start代码追踪一下

package main

import (
  "github.com/urfave/negroni"
  "net/http"
  "fmt"
)

func main() {
  mux := http.NewServeMux()
  mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
    fmt.Fprintf(w, "Welcome to the home page!")
  })

  n := negroni.Classic()
  n.UseHandler(mux)
  n.Run(":3000")
}

可以看到这里在UseHandler这里传入了HandleFunc(虽然类型和我们刚刚看到的Negroni定义的Handler不一样),我们尝试追踪一下UseHandler()

// UseHandler adds a http.Handler onto the middleware stack. Handlers are invoked in the order they are added to a Negroni.
func (n *Negroni) UseHandler(handler http.Handler) {
    n.Use(Wrap(handler))
}

// UseHandlerFunc adds a http.HandlerFunc-style handler function onto the middleware stack.
func (n *Negroni) UseHandlerFunc(handlerFunc func(rw http.ResponseWriter, r *http.Request)) {
    n.UseHandler(http.HandlerFunc(handlerFunc))
}

这里我们可以看到两个差不多的函数(后面一个本质上是调用前一个实现相同功能),这里传入的是http包的Handler类型,我们看一下Wrap()函数

// Wrap converts a http.Handler into a negroni.Handler so it can be used as a Negroni
// middleware. The next http.HandlerFunc is automatically called after the Handler
// is executed.
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)
    })
}

// WrapFunc converts a http.HandlerFunc into a negroni.Handler so it can be used as a Negroni
// middleware. The next http.HandlerFunc is automatically called after the Handler
// is executed.
func WrapFunc(handlerFunc http.HandlerFunc) Handler {
    return HandlerFunc(func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
        handlerFunc(rw, r)
        next(rw, r)
    })
}

可以看到这里Wrap()函数将http.Handler类型转为一个执行完本次handler然后执行next对应的handler的Negroni包的Handler类型
接着我们看一下UseHandler函数里面调用的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)
}

这里将传进来的handler加入handlers切片,然后调用build函数建立middleware,我们看一下build函数以及剩下的相关函数

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{},
    }
}

可以看到这是一个简单的递归过程,把handler拼成链表,然后建立middleware,至此我们可以看到Negroni库就是将你传进去的函数建成链表,然后由于Wrap()函数,默认会调用next(),也就是handler构成的链会一直调用到最后一个空的函数(即上示的voidMiddleware()返回的函数),当http包调用接口的时候,Negroni会执行middleware头指针(这只是类比)的handler然后一直往后面调用,这就是我们一开始给出的那张结构图了。

剩下的一些小细节

注意到刚刚的UseHandler等函数都是默认一直执行next的,那么有没有不执行next的呢,这里Negroni库提供了一个方法给你不调用next

func (n *Negroni) UseFunc(handlerFunc func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc)) {
    n.Use(HandlerFunc(handlerFunc))
}

这里很显然就必须传入该包定义的Handler类型的函数作为参数。
剩下的还有Negroni的几个构造函数和Run之类的就不多讲,这里稍微看看就好

gofunc New(handlers ...Handler) *Negroni {
    return &Negroni{
        handlers:   handlers,
        middleware: build(handlers),
    }
}

这是简单的New
然后这是类似与在尾部加上handler的构造函数

func (n *Negroni) With(handlers ...Handler) *Negroni {
    return New(
        append(n.handlers, handlers...)...,
    )
}

然后是Classical,这里面的logger等都在该库另外的go文件实现了,这是Negroni内置的另外三个类型

func Classic() *Negroni {
    return New(NewRecovery(), NewLogger(), NewStatic(http.Dir("public")))
}
版权声明:本文来源CSDN,感谢博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/caijhBlog/article/details/78507334
站方申明:本站部分内容来自社区用户分享,若涉及侵权,请联系站方删除。
  • 发表于 2020-03-07 21:22:25
  • 阅读 ( 1168 )
  • 分类:Go

0 条评论

请先 登录 后评论

官方社群

GO教程

猜你喜欢