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")))
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章