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.ServeHTTPmux.handler這兩個函數源碼,這個簡單而蛋疼的默認路由就躍然紙上。 對於路由,我們沒必要自己寫ServeHttp和match規則,因為太麻煩了。 所以,我們google下 httprouter這個包。輪子都造好了。