av激情亚洲男人的天堂国语,日韩欧美精品一中文字幕,无码av一区二区三区无码,国产又色又爽又刺激的a片,国产又色又爽又刺激的a片

用20行代碼寫出清晰易用的Go中間件API

在使用 Go 編寫復雜的服務(wù)時,您將遇到一個典型的主題是中間件。這個話題在網(wǎng)上被討論了一次又一次。本質(zhì)上,中間件允許我們做了如下事情:

創(chuàng)新互聯(lián)基于成都重慶香港及美國等地區(qū)分布式IDC機房數(shù)據(jù)中心構(gòu)建的電信大帶寬,聯(lián)通大帶寬,移動大帶寬,多線BGP大帶寬租用,是為眾多客戶提供專業(yè)四川聯(lián)通機房服務(wù)器托管報價,主機托管價格性價比高,為金融證券行業(yè)服務(wù)器托管,ai人工智能服務(wù)器托管提供bgp線路100M獨享,G口帶寬及機柜租用的專業(yè)成都idc公司。

  • 攔截 ServeHTTP 調(diào)用,執(zhí)行任意代碼
  • 對調(diào)用鏈(Continuation Chain) 上的請求/響應流進行更改
  • 打斷中間件鏈,或繼續(xù)下一個中間件攔截器并最終到達真正的請求處理器

這些與 express.js 中間件所做的工作非常類似。我們探索了各種庫,找到了接近我們想要的現(xiàn)有解決方案,但是他們要么有不要的額外內(nèi)容,要么不符合我們的品位。顯然,我們可以在 express.js 中間件的啟發(fā)下,寫出 20 行代碼以下的更清晰的易用的 API(Installation API)

抽象

在設(shè)計抽象時,我們首先設(shè)想如何編寫中間件函數(shù)(下文開始稱為攔截器),答案非常明顯:

 
 
 
  1. func NewElapsedTimeInterceptor() MiddlewareInterceptor { 
  2. return func(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) { 
  3. startTime := time.Now() 
  4. defer func() { 
  5. endTime := time.Now() 
  6. elapsed := endTime.Sub(startTime) 
  7. // 記錄時間消耗 
  8. }() 
  9.  
  10. next(w, r) 
  11.  
  12. func NewRequestIdInterceptor() MiddlewareInterceptor { 
  13. return func(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) { 
  14. if r.Headers.Get("X-Request-Id") == "" { 
  15. r.Headers.Set("X-Request-Id", generateRequestId()) 
  16.  
  17. next(w, r) 

它們看起來就像 http.HandlerFunc,但有一個額外的參數(shù) next,該函數(shù)(參數(shù))會繼續(xù)處理請求鏈。這將允許任何人像編寫類似 http.HandlerFunc 的簡單函數(shù)一樣寫攔截器,它可以攔截調(diào)用,執(zhí)行所需操作,并在需要時傳遞控制權(quán)。

接下來,我們設(shè)想如何將這些攔截器連接到 http.Handler 或 http.HandlerFunc 中。為此,首先要定義 MiddlewareHandlerFunc,它只是 http.HandlerFunc 的一種類型。(type MiddlewareHandlerFunc http.HandlerFunc)。這將允許我們在 http.HandlerFunc 棧上之上構(gòu)建一個更好的 API?,F(xiàn)在給定一個 http.HandlerFunc 我們希望我們的鏈式 API 看起來像這樣:

 
 
 
  1. func HomeRouter(w http.ResponseWriter, r *http.Request) { 
  2. // 處理請求 
  3.  
  4. // ... 
  5. // 在程序某處注冊 Hanlder 
  6. chain := MiddlewareHandlerFunc(HomeRouter). 
  7. Intercept(NewElapsedTimeInterceptor()). 
  8. Intercept(NewRequestIdInterceptor()) 
  9.  
  10. // 像普通般注冊 HttpHandler 
  11. mux.Path("/home").HandlerFunc(http.HandlerFunc(chain)) 

將 http.HandlerFunc 傳遞到 MiddlewareHandlerFunc,然后調(diào)用 Intercept 方法注冊我們的 Interceptor。Interceptor 的返回類型還是 MiddlewareHandlerFunc,它允許我們再次調(diào)用 Intercept。

使用 Intercept 組合需要注意的一件重要事情是執(zhí)行的順序。由于 chain(responseWriter, request)是間接調(diào)用最后一個攔截器,攔截器的執(zhí)行是反向的,即它從尾部的攔截器一直返回到頭部的處理程序。這很有道理,因為你在攔截調(diào)用時,攔截器應該要在真正的請求處理器之前執(zhí)行。

簡化

雖然這種反向鏈系統(tǒng)使抽象更加流暢,但事實證明,大多數(shù)情況下 s 我們有一個預編譯的攔截器數(shù)組,能夠在不同的 handlers 之間重用。同樣,當我們將中間件鏈定義為數(shù)組時,我們自然更愿意以它們執(zhí)行順序聲明它們(而不是相反的順序)。讓我們將這個數(shù)組攔截器稱為中間件鏈。我們希望我們的中間件鏈看起來有點像:

 
 
 
  1. // 調(diào)用鏈或中間件可以按下標的順序執(zhí)行 
  2. middlewareChain := MiddlewareChain{ 
  3. NewRequestIdInterceptor(), 
  4. NewElapsedTimeInterceptor(), 
  5.  
  6. // 調(diào)用所有以 HomeRouter 結(jié)尾的中間件 
  7. mux.Path("/home").Handler(middlewareChain.Handler(HomeRouter)) 

實現(xiàn)

一旦我們設(shè)計好抽象的概念,實現(xiàn)就顯得簡單多了

 
 
 
  1. package middleware 
  2.  
  3. import "net/http" 
  4.  
  5. // MiddlewareInterceptor intercepts an HTTP handler invocation, it is passed both response writer and request 
  6. // which after interception can be passed onto the handler function. 
  7. type MiddlewareInterceptor func(http.ResponseWriter, *http.Request, http.HandlerFunc) 
  8.  
  9. // MiddlewareHandlerFunc builds on top of http.HandlerFunc, and exposes API to intercept with MiddlewareInterceptor. 
  10. // This allows building complex long chains without complicated struct manipulation 
  11. type MiddlewareHandlerFunc http.HandlerFunc 
  12.  
  13.  
  14. // Intercept returns back a continuation that will call install middleware to intercept 
  15. // the continuation call. 
  16. func (cont MiddlewareHandlerFunc) Intercept(mw MiddlewareInterceptor) MiddlewareHandlerFunc { 
  17. return func(writer http.ResponseWriter, request *http.Request) { 
  18. mw(writer, request, http.HandlerFunc(cont)) 
  19.  
  20. // MiddlewareChain is a collection of interceptors that will be invoked in there index order 
  21. type MiddlewareChain []MiddlewareInterceptor 
  22.  
  23. // Handler allows hooking multiple middleware in single call. 
  24. func (chain MiddlewareChain) Handler(handler http.HandlerFunc) http.Handler { 
  25. curr := MiddlewareHandlerFunc(handler) 
  26. for i := len(chain) - 1; i >= 0; i-- { 
  27. mw := chain[i] 
  28. curr = curr.Intercept(mw) 
  29.  
  30. return http.HandlerFunc(curr) 

因此,在不到 20 行代碼(不包括注釋)的情況下,我們就能夠構(gòu)建一個很好的中間件庫。它幾乎是簡簡單單的,但是這幾行連貫的抽象實在是太棒了。它使我們能夠毫不費力地編寫一些漂亮的中間件鏈。希望這幾行代碼也能激發(fā)您的中間件體驗。


分享文章:用20行代碼寫出清晰易用的Go中間件API
轉(zhuǎn)載注明:http://uogjgqi.cn/article/ccdhhps.html
掃二維碼與項目經(jīng)理溝通

我們在微信上24小時期待你的聲音

解答本文疑問/技術(shù)咨詢/運營咨詢/技術(shù)建議/互聯(lián)網(wǎng)交流