Go語言經典庫流量分析(三)| Gorilla Handlers 詳細介紹

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

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

在我們編寫web服務端程式的時候,我們可能會對一些甚至全部的Http Request統一處理,比如我們記錄每個訪問的Request,對提交的Form表單進行映射等,要達到這些目的,比較優雅的做法是Http 中介軟體。

中介軟體,顧名思義,強調的是中間,他是一種業務無關的,在正常的的業務handler處理前後的,獨立的邏輯處理片段。一般調用順序如下:

1
ServeMux路由分發->調用中介軟體1->調用中介軟體2……->調用真正的業務處理邏輯

因為中介軟體非常獨立,可以我們不用的時候,去掉即可;需要用的時候,加上,並不會修改真正的業務處理邏輯代碼,可謂非常簡潔方便。

這裡我選用Gorilla Handlers這個中介軟體庫示範如何使用和定義一個中介軟體,這一篇主要講Gorilla Handlers的使用,下一篇會講Gorilla Handlers裡每個中介軟體的實現原理。

安裝

Gorilla Handlers是一個很簡單,但是很有代表性的中介軟體庫,所以拿他來分析,更容易理解handler中介軟體。在使用之前,我們要先安裝,該中介軟體庫已經託管在Github上,所以我們直接使用go get即可。

1
$ go get github.com/gorilla/handlers

安裝之後,我們在代碼裡使用如下代碼即可匯入使用。

1
import "github.com/gorilla/handlers"

Gorilla Handlers以函數的方式提供了好幾種中介軟體,比如CombinedLoggingHandler、CompressHandler、ContentTypeHandler、LoggingHandler等,下面我們就一一介紹他們。

LoggingHandler

我們應該都用過Nginx,Nginx的訪問日誌,類似於如下這樣:

1
[05/Aug/2017:21:06:24 +0800] "GET /favicon.ico HTTP/1.1" 200 11

從中我們可以看到訪問的什麼資源,使用的什麼協議,返回的HTTP狀態以及請求的大小是多少,這種一種日誌風格,和Apache Common Log Format很像,LoggingHandler中介軟體就是幫我們做這個事情的。

它可以記錄request的日誌,輸出到一個io.Writer裡。

123456789101112131415161718
func main() {http.Handle("/",useLoggingHandler(handler()))http.ListenAndServe(":1234",nil)}func handler() http.Handler{return http.HandlerFunc(myHandler)}func myHandler(rw http.ResponseWriter, r *http.Request) {rw.WriteHeader(http.StatusOK)io.WriteString(rw,"Hello World")}func useLoggingHandler(next http.Handler) http.Handler {return handlers.LoggingHandler(os.Stdout,next)}

我這裡的io.Writer是一個os.Stdout,也就是標準的控制台輸出,所以我們訪問http://localhost:1234/的時候,可以看到控制台列印的Request日誌資訊輸出。

12
::1 - - [05/Aug/2017:21:06:24 +0800] "GET / HTTP/1.1" 200 11::1 - - [05/Aug/2017:21:06:24 +0800] "GET /favicon.ico HTTP/1.1" 200 11

handlers.LoggingHandler函數的參數我們可以看出,它接受一個Handler,然後返回一個Handler,其實就是對現有的Handler的一次封裝,這就是中介軟體。

這裡的輸出參數類型是io.Writer,所以我們可以輸出檔案等實現了該介面的任何類型。

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

CombinedLoggingHandler

還有一種日誌格式,這種日誌格式輸出的日誌資訊更詳細,更全面,比如包含UA等資訊,這種格式被稱為Apache Combined Log Format。

CombinedLoggingHandler就是為我們提供輸出一種這種格式的中介軟體,使用方式和LoggingHandler一樣。

123
func useCombinedLoggingHandler(next http.Handler) http.Handler {return handlers.CombinedLoggingHandler(os.Stdout,next)}

看下這個中介軟體輸出的日誌資訊

1
::1 - - [05/Aug/2017:21:39:45 +0800] "GET /favicon.ico HTTP/1.1" 200 11 "http://localhost:1234/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.78 Safari/537.36"

UA+HOST,日誌資訊更全面了。

CompressHandler

這是一個壓縮response的中介軟體,支援gzip和deflate壓縮。如果用戶端的要求標頭裡包含Accept-Encoding,並且值為gzip或者deflate,該中介軟體就會壓縮返回的response,這樣就可以減少response的大小,減少響應的時間,使用訪問也很簡單,這裡簡單舉個例子。

123456789101112131415161718
func main() {http.Handle("/gzip",useCompressHandler(handler()))http.ListenAndServe(":1234",nil)}func handler() http.Handler{return http.HandlerFunc(myHandler)}func myHandler(rw http.ResponseWriter, r *http.Request) {rw.WriteHeader(http.StatusOK)rw.Header().Set("Content-Type", "text/plain")io.WriteString(rw,"Hello World")}func useCompressHandler(next http.Handler) http.Handler {return handlers.CompressHandler(next)}

這裡尤其注意的是我們返回的response的內容類型要特別指定一下,不然就會被自動解析為gzip,就變成下載一個gz檔案了。我這裡強制指定文本類型,這樣就可以看到返回的內容Hello World

該中介軟體還有一個函數CompressHandlerLevel可以指定壓縮的層級,層級是gzip.BestSpeed和gzip.BestCompression之間的值,如果大家不想用預設壓縮層級,可以使用這個函數指定。

還記得Nginx可以開啟Gzip加速吧,差不多也是這麼個實現。

ContentTypeHandler

這也是一個很有意思的中介軟體,他的作用是只處理支援的內容類型,如果不支援,則返回415狀態代碼。該中介軟體只對PUT,POST,PATCH方法有效,其他方法則不做處理,也就相當於沒有使用這個中介軟體。

123
func useContentTypeHandler(next http.Handler) http.Handler {return handlers.ContentTypeHandler(next,"application/x-www-form-urlencoded")}

最後一個參數是可變參數,我們可以指定多個ContextType類型,這些類型是被我們支援的,其他類型則不支援。如果我們使用PUT、POST、PATCH方法提交的請求的內容類型不在我們支援的內容類型範圍內,則返回415錯誤。

CanonicalHost

這是一個重新導向的中介軟體,他可以把一個Request請求重新定向到另外一個網域名稱上,並且會帶上原請求的Path和Query。

123456789101112131415161718
func main() {http.Handle("/flysnow",useCanonicalHost(handler()))http.ListenAndServe(":1234",nil)}func handler() http.Handler{return http.HandlerFunc(myHandler)}func myHandler(rw http.ResponseWriter, r *http.Request) {rw.WriteHeader(http.StatusOK)rw.Header().Set("Content-Type", "text/plain")io.WriteString(rw,"Hello World")}func useCanonicalHost(next http.Handler) http.Handler {return handlers.CanonicalHost("http://www.flysnow.org/",http.StatusFound)(next)}

上面的樣本,當我們在瀏覽器內輸入http://localhost:1234/flysnow的訪問的時候,會自動跳轉到http://www.flysnow.org/flysnow

小結

其他的一些不常用的中間的使用方式也類似,大家可以自己看下文檔測試下。Go Http的中介軟體,有點類似於HTTP的攔截器,通過一層層的封裝,我們可以組成一個中介軟體的處理鏈,便於我們處理我們需要處理的通用性問題,如果哪個中介軟體不想要,去掉即可,不用對業務代碼做任何修改。

例子中的示範,都是一個url對應一個中介軟體的處理,這個主要是為了示範方面。如果我們相對所有的請求都使用某個中介軟體怎麼做呢?肯定不能使用我們例子中的方式了,因為這樣會寫很多個。

對於以上這種方式,我們可以藉助HTTP Mux路由,因為一個路由也是一個Handler,只用對這個路由應用中介軟體,就可以攔截處理所有的請求了。

下一篇開始分享這些常用中介軟體的實現原理和原始碼的分析。

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.