Go предоставляет базовые возможности по маршрутизации. Однако этих возможностей, как правило, было недостаточно, особенно в тех случаях, когда необходимо выделять сегменты из запрошенного адреса URL и каким-то образом обрабатывать их. В этом случае мы можем воспользоваться рядом существующих инструментов, одним из которых является Gorilla. (Официальный сайт http://www.gorillatoolkit.org/) Это пакет разработчика специально для упрощения создания веб-приложений на языке Go, который, в свою очередь, включает ряд пакетов:
gorilla/context: предназначен для создания глобальных переменных из тела запроса
gorilla/rpc: представляет реализацию протокола RPC-JSON
gorilla/websocket: реализует протокол WebSocket
gorilla/schema: позволяет создавать из значений формы единую структуру
gorilla/securecookie: позволяет создавать зашифрованные куки, которые применяются при аутентификации
gorilla/sessions: обеспечивает поддержку сессий
gorilla/mux: позволяет определять более сложные маршруты, которые могут использовать регулярные выражения
gorilla/reverse: используется для создания регулярных выражений для маршрутов
В данном случае задействуем возможности по созданию маршрутов с помощью gorilla/mux и для установки данного пакета выполним в командной строке/терминале следующую команду:
go get github.com/gorilla/mux
Определим следующий код сервера:
package main import ( "fmt" "net/http" "github.com/gorilla/mux" ) func productsHandler(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) id := vars["id"] response := fmt.Sprintf("Product %s", id) fmt.Fprint(w, response) } func main() { router := mux.NewRouter() router.HandleFunc("/products/{id:[0-9]+}", productsHandler) http.Handle("/",router) fmt.Println("Server is listening...") http.ListenAndServe(":8181", nil) }
Для определения маршрутов с помощью gorilla/mux применяется функция mux.NewRouter(). У возвращаемого этой функцией объекта мы можем вызвать метод HandleFunc, который сопоставляет маршрут с определенным обработчиком.
Первый параметр представляет шаблон пути запроса. В фигурных скобках мы можем определить параметр в формате имя_параметра:регулярное_выражение
.
Регулярное выражение определять необязательно, но если оно определено, то параметр должен соответствовать этому выражению. То есть в данном случае
параметр id должен представлять числовое значение.
Второй параметр - функция обработчика запросов, по указанному в первом параметре маршруту. Подобная функция должна иметь два параметра: func(w http.ResponseWriter, r *http.Request)
.
В данном случае функция обработчика - productsHandler - получает параметры пути запроса через функцию mux.Vars.
Затем из полученного объекта можно извлечь название нужного нам параметра: id := vars["id"]
. Название параметра здесь то же самое, что в определение маршрута.
В итоге при обращении к приложению по запросу localhost:8181/products/2 мы получим следующий вывод:
Если бы мы захотели бы сделать то же самое, но штатными средствами, которые есть в Go без gorilla/mux, то нам бы пришлось писать дополнительный код для парсинга запрошенного пути.
Подобным образом мы можем использовать несколько параметров:
package main import ( "fmt" "net/http" "github.com/gorilla/mux" ) func productsHandler(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) id := vars["id"] cat := vars["category"] response := fmt.Sprintf("Product category=%s id=%s", cat, id) fmt.Fprint(w, response) } func main() { router := mux.NewRouter() router.HandleFunc("/products/{category}/{id:[0-9]+}", productsHandler) http.Handle("/",router) fmt.Println("Server is listening...") http.ListenAndServe(":8181", nil) }
В данном случае определены два параметра: id и category.
Можно определять несколько маршрутов, которые могут использовать либо различные, либо одни и те же обработчики:
package main import ( "fmt" "net/http" "github.com/gorilla/mux" ) func productsHandler(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) id := vars["id"] response := fmt.Sprintf("id=%s", id) fmt.Fprint(w, response) } func indexHandler(w http.ResponseWriter, r *http.Request) { fmt.Fprint(w, "Index Page") } func main() { router := mux.NewRouter() router.HandleFunc("/products/{id:[0-9]+}", productsHandler) router.HandleFunc("/articles/{id:[0-9]+}", productsHandler) router.HandleFunc("/", indexHandler) http.Handle("/",router) fmt.Println("Server is listening...") http.ListenAndServe(":8181", nil) }