go web: 3 中間件和路由
- 2019 年 11 月 21 日
- 筆記
中間件
中間件的本質來看,就是在執行handler的前(後)先執行一個自定義的handler而已。那問題變成,go web中,每個handler是怎麼執行的。
答案在mux := http.NewServeMux()
中,稍微閱讀下源碼,我們就能得出,mux對象中有個ServeHTTP(w, r)
方法。這就秘密所在。
根據go的鴨子類型特性,我們完全可以實現一個結構,然後讓它擁有ServeHTTP(w, r)
方法。把這個結構替換掉http.Server
對象中的Handler
,就能自定義hander的執行。既然都能控制handler運行了,中間件什麼的還不是小case。
然而還能更簡單,可愛的go語言還在http包中,提供了一個http.HandlerFunc(ourFunc)
方法,它能把簽名為func(w http.ResponseWriter, r *http.Request)
的函數轉化為一個handler,沒錯,就是上面mux相同的類型。 要實現自己的mux,可以只是一個簡單的函數:
// myHost 做中間件 func myHost(handler http.Handler) http.Handler { ourFunc := func(w http.ResponseWriter, r *http.Request) { //記錄時間 start := time.Now() handler.ServeHTTP(w, r) logger.Infoln( fmt.Sprintf("%s %s %s", r.Method, r.URL, time.Now().Sub(start))) } return http.HandlerFunc(ourFunc) }
這個「記錄時間」的操作,不就是最簡單的中間件嗎? main.go中的調用則改成:
mux := http.NewServeMux() mh := myHost(mux) server := http.Server{ Addr: fmt.Sprintf(":%d", options.GetInt("port")), Handler: mh, ReadTimeout: 3 * time.Second, WriteTimeout: 5 * time.Second, } // 開始添加路由 mux.HandleFunc("/hi", test.SayHello) server.ListenAndServe()
路由
既然我們能通過hack ServeHTTP
來控制handler的調用,那實現路由還不是順水推舟。 在server.go中看看mux.ServeHTTP
和mux.handler
這兩個函數源碼,這個簡單而蛋疼的默認路由就躍然紙上。 對於路由,我們沒必要自己寫ServeHttp和match規則,因為太麻煩了。 所以,我們google下 httprouter
這個包。輪子都造好了。