使用gorilla/mux加強Go HTTP服務器的路由能力

1_rYCXrSu36OldVLXzHy-1FA.png

今天這篇文章咱們將會爲咱們以前編寫的HTTP服務器加上覆雜路由的功能以及對路由進行分組管理。在以前的文章《深刻學習用 Go 編寫HTTP服務器》中詳細地講了使用net/http進行路由註冊、監聽網絡鏈接、處理請求、安全關停服務的實現方法,使用起來很是方便。可是net/http有一點作的不是很是好的是,它沒有提供相似URL片斷解析、路由參數綁定這樣的複雜路由功能。好在在Go社區中有一個很是流行的gorilla/mux包,它提供了對複雜路由功能的支持。在今天這篇文章中咱們將探究如何用gorilla/mux包來建立具備命名參數、GET/POST處理、分組前綴、限制訪問域名的路由。git

安裝gorilla/mux

咱們在以前寫的HTTP服務的代碼根目錄,使用go get命令從GitHub安裝軟件包,以下所示:github

go get  github.com/gorilla/mux

在《深刻學習用 Go 編寫HTTP服務器》中咱們介紹過路由註冊、匹配和最後處理函數的調用都是由ServeMux(服務複用器)來完成的,並且咱們還本身定義了複用器用以替換默認的DefaultServeMux。一樣的gorilla/mux包也是爲咱們提供了一個複用器。這個複用器擁有不少功能用以提高編寫Web應用的效率,並且與標準的http.ServeMux兼容。正則表達式

使用gorilla/mux

建立路由器

能夠像下面這樣建立一個路由器安全

router := mux.NewRouter()

會返回一個mux.Router實例,mux.Router將傳入的請求與已註冊路由列表進行匹配,併爲與URL或其餘條件匹配的路由調用處理程序。主要特色是:服務器

  • 能夠根據URL主機,路徑,路徑前綴,Header頭、查詢值,HTTP方法進行路由匹配,或是使用自定義匹配器。
  • URL主機,路徑和查詢值能夠是帶有可選正則表達式的變量。
  • 路由能夠被用做子路由,只有父路由匹配後纔會嘗試匹配子路由。這對於定義路由組很是有用,路由組能夠共享主機、路徑前綴、或者其餘常見的屬性。
  • 它實現了http.Handler接口,所以與標準的http.ServeMux徹底兼容。

註冊路由處理程序

咱們將以前程序裏自定義的服務複用器替換成上面建立好mux.Router,併爲其註冊路由處理器。網絡

type helloHandler struct{}
func (*helloHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "Hello World")
}
func WelcomeHandler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "Welcome!")
}

func main() {
    router := mux.NewRouter()
    router.Handle("/", &helloHandler{})
  router.HandleFunc("/welcome", WelcomeHandler)
  ......
}

以前咱們是用http.Hanlehttp.HandleFunc註冊處理程序的,這裏直接換成router.Hanlerouter.HanleFunc便可,很方便。函數

定義帶命名參數的路由

使用mux.Router的最大優點是能夠從請求URL中提取分段,而後做爲命名參數傳入路由處理程序供使用。學習

接下來爲咱們的程序註冊一個路由處理器,讓服務器可以處理URL/names/Gorge/countries/NewZealand的請求:spa

router.HandleFunc("/names/{name}/countries/{country}", func(writer http.ResponseWriter, request *http.Request) {
            ......
})

接下來在處理函數中使用mux.Vars()函數從這些URL分段中獲取數據。該函數以http.Request爲參數並返回一個URL分段名爲鍵,提取的數據爲值的字典。code

func(writer http.ResponseWriter, request *http.Request) {
        vars := mux.Vars(request)
        name := vars["name"]
        country := vars["country"]
        fmt.Fprintf(writer, "This guy named %s, was coming from %s .", name, country)
})

讓服務器使用咱們建立的路由器

這個設置很簡單,若是沒有自定義http.Server對象,使用http.ListenAndServe(":8000", router),使用本身定義的`http.Server 對象時則是:

server := &http.Server{
    Addr:    ":8080",
    Handler: router,
}

這個和咱們把自定義的服務複用器傳遞給http.Server沒有任何區別。

改造完後咱們以前寫的HTTP服務器就能夠根據具體的 URL 動態地構造響應。關鍵字回覆http02可得到完整的源代碼

其餘gorilla/mux路由器的經常使用功能

設置路由的HTTP方法

限制路由處理器只處理指定的HTTP方法的請求:

router.HandleFunc("/books/{title}", CreateBook).Methods("POST")
router.HandleFunc("/books/{title}", ReadBook).Methods("GET")
router.HandleFunc("/books/{title}", UpdateBook).Methods("PUT")
router.HandleFunc("/books/{title}", DeleteBook).Methods("DELETE")

上面的就是一組能夠響應具體HTTP方法的RESTful風格的接口的路由。

設置路由的域名

限制路由處理器只處理訪問指定域名加路由的請求:

router.HandleFunc("/books/{title}", BookHandler).Host("www.mybookstore.com")

限制HTTP 方案

將請求處理程序可響應的HTTP 方案限制爲http或者https

router.HandleFunc("/secure", SecureHandler).Schemes("https")
router.HandleFunc("/insecure", InsecureHandler).Schemes("http")

設置路徑前綴和子路由

bookrouter := router.PathPrefix("/books").Subrouter()
bookrouter.HandleFunc("/", AllBooks)
bookrouter.HandleFunc("/{title}", GetBook)

使用gorilla/mux改進咱們的HTTP服務器

接下來咱們使用gorilla/mux對咱們以前寫的HTTP服務器作一下改進,以前咱們全部程序都放在了main.go中,如今咱們的程序還很小,因此咱們先不把項目目錄規劃的太複雜,先經過文件作下簡單的職責劃分,新建兩個文件router.gohandler.go分別用來存放路由註冊的邏輯和路由對應的處理器函數,兩個文件的示例內容以下。

handler.go:

package main

import (
    "fmt"
    "github.com/gorilla/mux"
    "net/http"
)

type HelloHandler struct{}

func (*HelloHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "Hello World")
}

func ShowVisitorInfo(writer http.ResponseWriter, request *http.Request) {
    vars := mux.Vars(request)
    name := vars["name"]
    country := vars["country"]
    fmt.Fprintf(writer, "This guy named %s, was coming from %s .", name, country)
}

router.go:

package main

import (
    "github.com/gorilla/mux"
)

func RegisterRoutes(r *mux.Router) {
    indexRouter := r.PathPrefix("/index").Subrouter()
    indexRouter.Handle("/", &HelloHandler{})

    userRouter := r.PathPrefix("/user").Subrouter()
    userRouter.HandleFunc("/names/{name}/countries/{country}", ShowVisitorInfo)
}

router.go中咱們將路由分爲indexuser兩組,在兩個路由組上分別定義路由。將這部分封裝在一個導出函數RegisterRoutes供調用。這樣即便之後路由註冊的程序要放到單獨的目錄裏也能夠供外部調用。

整理完後咱們的main.go中就會變的很簡潔:

func main() {
   //mux := http.NewServeMux()
   //mux.Handle("/", &helloHandler{})
   muxRouter := mux.NewRouter()

   RegisterRoutes(muxRouter)

   server := &http.Server{
      Addr:    ":8080",
      Handler: muxRouter,
   }

   ......
   err := server.ListenAndServe()
   ......
}

關注公衆號回覆go-http-02獲取本文中完整的示例代碼。

前文回顧:深刻學習用 Go 編寫HTTP服務器

喜歡個人文章,幫忙轉發點贊,如在實踐過程當中遇到什麼問題可在下方給我留言。

tWbHIMFsM3.png

相關文章
相關標籤/搜索