Go語言經典庫流量分析(六)| Negroni 中介軟體(二)

來源:互聯網
上載者:User
這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。

Go語言經典庫流量分析,未完待續,歡迎掃碼關注公眾號flysnow_org或者網站http://www.flysnow.org/,第一時間看後續系列。覺得有協助的話,順手分享到朋友圈吧,感謝支援。

上一篇 Go語言經典庫流量分析(五)| Negroni 中介軟體(一) 中介紹了Negroni中間的入門使用和一些介紹,比如如何添加中間等,中介軟體的路由等。這一篇主要講原理,比如如何構建的中間處理鏈,如何編寫自己的中介軟體等。

Negroni Handler處理器

本質上來說Negroni是一個HTTP Handler,因為他實現了HTTP Handler介面,所以他可以被http.ListenAndServe使用,其次Negroni本身內部又有一套自己的Handler處理鏈,通過他們可以達到處理http請求的目的,這些Handler處理鏈中的處理器,就是一個個中介軟體。

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

以上代碼,是Negroni實現了HTTP的Handler,這樣就和標註庫裡的http無縫整合了。實現了HTTP Handler,對於HTTP Request來說,就有一個統一的入口,所有的對HTTP Requet的處理,都會被Negroni通過ServeHTTP方法轉交給Negroni內部註冊的中介軟體。

12345
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 Handler非常相似,唯一不同的是多了一個next參數,這個next參數是組成中介軟體處理鏈的核心。

如何構建中介軟體處理鏈

我們已經知道了Negroni有自己的一套Handler中介軟體處理鏈,那麼這個處理鏈和如何構建的呢?要想解開這個謎底,我們先看下Negroni如何註冊一個中介軟體的。

12345678910111213
type Negroni struct {middleware middlewarehandlers   []Handler}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方法的時候,會把Negroni的Handler存在自己的handlers欄位中,這是一個Slice類型欄位,可以儲存我們存放的Negroni Handler。同時會基於這個存放Negroni Handler的Slice構建中介軟體處理鏈middleware

1234
type middleware struct {handler Handlernext    *middleware}

middleware struct有很簡單,有兩個欄位,一個是當前的Negroni Handler,一個是指向下一個middleware的指標next。有了這樣一個middleware struct,就可以構建一個完美的中介軟體處理鏈了。

1234567891011121314151617181920
func build(handlers []Handler) middleware {var next middlewareif 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{},}}

以上代碼就是構建一個中介軟體處理鏈的邏輯,這是一個遞迴的函數,邏輯比較簡單。

handlers參數為空白的時候,直接通過voidMiddleware函數返回一個空的middleware
handlers參數只有1個處理器的時候,構建的milldeware就沒有next了,所以next是通過voidMiddleware函數獲得的,然後再通過return middleware{handlers[0], &next}組成產生的middleware並返回。

最後一種情況,就是有1個以上的Negroni Handler,那就通過build函數迴圈遞迴了,從第2個Handler開始,不停的往後遞迴處理,所以最先被添加的Negroni Handler會被放在中介軟體處理鏈的前面,也就意味著會被優先執行。

中介軟體如何被調用

構建好了處理器鏈,那麼這些中介軟體如何被調用的呢?前面的章節,我們講了Negroni是一個HTTP Handler,所以總的入口在ServeHTTP方法裡。

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

從以上代碼可以看出,調用了middleware.ServeHTTP方法,這就是中介軟體被執行的開始。

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

middleware.ServeHTTP方法調用middleware中當前handler的ServeHTTP方法執行我們自己寫的中介軟體處理邏輯。

12345
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)}

又回到這裡了吧,handler的ServeHTTP方法執行,本質上就是執行的我們自己定義的negroni.HandlerFunc。

當前的中介軟體被執行了,那麼下一個如何被觸發的?這就是我們自己定義的中介軟體函數中的next參數了。我們在自己的中介軟體處理結束後,如果覺得有必要,就需要調用next函數,繼續執行下一個中介軟體,如果我們不調用next函數,那麼中介軟體鏈的處理,到這裡就斷了。看一個自訂中介軟體的例子。

1234567
func (l *Logger) ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {start := time.Now()next(rw, r)//省略無關代碼}

這是Negroni內建的log中介軟體的實現,可以看到,它調用了next(rw, r)函數,讓中介軟體處理鏈繼續執行。這個next(rw, r)是什麼呢?其實前面我們講過。

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

next函數的調用,就是對下一個middlewareServeHTTP的再次調用,這是一個遞迴,也是中介軟體處理鏈設計的巧妙之處,靈活控制,自由的選擇是否調用下個中介軟體。

Go語言經典庫流量分析,未完待續,歡迎掃碼關注公眾號flysnow_org或者網站http://www.flysnow.org/,第一時間看後續系列。覺得有協助的話,順手分享到朋友圈吧,感謝支援。

http Handler和negroni Handler之間的轉換

在剛介紹Negroni的時候,我們知道,它是相容HTTP Handler的,Negroni可以直接把HTTP Handler轉換為Negroni HTTP,讓我們可以直接使用HTTP Handler作為Negroni的中介軟體,下面我們看下是如何轉換的。

1234567
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))}

Negroni提供兩個方法,分別相容http.Handlerhttp.HandlerFuncUseHandlerFunc方法本質上還是調用的UseHandler方法,UseHandler方法實現的重點就是Wrap(handler),它完成了http.Handler到negroni.Handler的轉換。

123456
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)})}

這個函數本質上是Negroni中介軟體的實現,它的代碼邏輯就是先執行http.Handler中介軟體的實現,然後調用next(rw, r)執行下一個中介軟體。

內建中介軟體介紹

Negroni內建了幾個中介軟體,當我們通過Classic函數建立一個*Negroni的時候,就會有

123
func Classic() *Negroni {return New(NewRecovery(), NewLogger(), NewStatic(http.Dir("public")))}

NewRecovery,NewLoggerNewStatic就是這幾個內建的中介軟體,都是實現了negroni handler而成的中介軟體,具體原始碼大家可以看下,這裡就不具體介紹了。

編寫自己的中介軟體

編寫自己的中介軟體,在Negroni可以採用兩種方式,一種是http.Handler的方式,這種方式優點是大家都熟悉,並且已經會了,缺點也有,就是不能控制中介軟體的處理鏈,預設是調用下一個中介軟體的,我們不能中斷。

另外一個就是實現negroni.Handler的方式,Negroni推薦的也是這種方式。

123456789101112131415161718192021222324252627282930
//Blog:www.flysnow.org//Wechat:flysnow_orgfunc main() {n := negroni.New()n.UseFunc(printAuthorInfo)router:=http.NewServeMux()router.Handle("/",handler())n.UseHandler(router)n.Run(":1234")}func printAuthorInfo(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc){fmt.Println("Blog:www.flysnow.org")fmt.Println("Wechat:flysnow_org")next(rw,r)}func handler() http.Handler{return http.HandlerFunc(myHandler)}func myHandler(rw http.ResponseWriter, r *http.Request) {rw.Header().Set("Content-Type", "text/plain")io.WriteString(rw,"Hello World")}

我們通過printAuthorInfo函數實現了一個Negroni Handler中介軟體,這個中介軟體很簡單,只是列印一些作者資訊,然後就執行下一個中介軟體。

使用的時候,我們通過n.UseFunc(printAuthorInfo)註冊這個中介軟體,我們啟動服務,訪問http://localhost:1234的時候,就可以在控制台看到如下資訊:

12
Blog:www.flysnow.orgWechat:flysnow_org

為了舉例,我這個中介軟體比較簡單,大家可以根據自己的需求實現滿足自己業務的中介軟體。

一些中介軟體介紹

Github上有很多專門為Negroni開發的第三方中介軟體,以配合Negroni的使用,比如gzip的,oauth2.0的等,大家可以通過如下連結查看第三方的中間列表:

https://github.com/urfave/negroni#third-party-middleware

小結

到這裡,Negroni這個中介軟體分析完了,可能還有一些沒有分析的,比如With方法,Run方法,他們都是比較簡單的,大家看下就可以了。

還有一個比較重要的是NewResponseWriter這個函數,它是對我們現在的NewResponseWriter的封裝,增加了一些額外的資訊,這個知識點我在這個篇 Go語言經典庫流量分析(四)| Gorilla Handlers 原始碼實現分析 文章裡詳細介紹過,就不再重複介紹了。

HTTP的中介軟體,就是一個HTTP的攔截器,Negroni對於該攔截器處理的更好,可以靈活控制,是否終端等,合理的使用Negroni,可以讓你事半功倍。

Go語言經典庫流量分析,未完待續,歡迎掃碼關注公眾號flysnow_org或者網站http://www.flysnow.org/,第一時間看後續系列。覺得有協助的話,順手分享到朋友圈吧,感謝支援。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.