HttpRouter
Адрес репозитория: julienschmidt/httprouter: A high performance HTTP request router that scales well (github.com)
В качестве компонента маршрутизации Gin используется HttpRouter, который также является лёгким и высокопроизводительным компонентом маршрутизации. Весь компонент состоит всего из трёх файлов .go, код очень лаконичный. Его основные особенности:
Однозначное сопоставление: Один запрос может быть сопоставлен только с нулём или одним маршрутом, что благоприятно для SEO-оптимизации.
Автоматическое исправление пути: Выбирайте любой стиль URL, который вам нравится. Даже если добавлен или пропущен слэш, произойдёт автоматическое перенаправление. Если есть ошибки регистра, поиск также проигнорирует регистр и выполнит правильное перенаправление.
Автоматический разбор параметров маршрута: Просто дайте имя сегменту пути, и маршрутизатор передаст вам динамические значения. Благодаря дизайну маршрутизатора накладные расходы на разбор параметров пути очень низки.
Нулевой мусор: В процессе распределения и планирования маршрутов не создаётся никакого мусора памяти.
Поддержка RestfulAPI: Дизайн маршрутизатора поощряет разумную многоуровневую Restful API.
Обработка ошибок: Можно установить обработчик ошибок для обработки исключений в запросах, маршрутизатор перехватит и запишет их, затем перенаправит на страницу ошибки.
Базовое использование
Как и в springboot, одна функция привязывается к одному URL и соответствует одному обработчику.
package main
import (
"fmt"
"github.com/julienschmidt/httprouter"
"log"
"net/http"
)
func Hello(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
fmt.Fprintf(w, "<h1>Hello World!")
}
func main() {
router := httprouter.New()
router.GET("/hello", Hello)
log.Fatal(http.ListenAndServe(":8080", router))
}Затем, используя браузер или любой инструмент тестирования интерфейсов, введите 127.0.0.1:8080, и вы увидите правильное содержимое. Мы можем видеть, что HttpRouter выполняет только маршрутизацию, фактически всё ещё используется компонент net/http по умолчанию. gin также работает аналогично, просто инкапсуляция немного глубже.
Именованные параметры
package main
import (
"fmt"
"github.com/julienschmidt/httprouter"
"log"
"net/http"
)
func Hello(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
fmt.Fprintf(w, "<h1>Hello World!")
}
func main() {
router := httprouter.New()
router.GET("/hello:name", Hello)
log.Fatal(http.ListenAndServe(":8080", router))
}На этот раз после маршрута добавлен :name, где name — это именованный параметр. Доступ к срезу параметров можно получить через httprouter.Params, можно получить параметр по индексу или через ByName(name). Аналогично, вы можете использовать http.Handler и http.HandlerFunc как httprouter.Handle, поскольку маршрутизатор реализует этот интерфейс. Например, следующий пример.
func Hello(w http.ResponseWriter, r *http.Request) {
params := httprouter.ParamsFromContext(r.Context())
//params := r.Context().Value(httprouter.ParamsKey) также можно
fmt.Fprintf(w, "hello, %s!\n", params.ByName("name"))
}Когда метод привязан к маршруту /user/:user, следующие несколько URL будут сопоставлены так:
/user/gordon сопоставление
/user/you сопоставление
/user/gordon/profile нет сопоставления
/user/ нет сопоставленияВы не можете зарегистрировать /user/new и /user/:user для одного и того же метода запроса. Каждый метод запроса должен быть независимым.
Захват всех параметров
Второй тип — захват всех параметров. Как следует из названия, они сопоставляют всё, поэтому должны находиться в конце Pattern.
Pattern: /src/*filepath
/src/ сопоставление
/src/somefile.go сопоставление
/src/subdir/somefile.go сопоставлениеПринцип работы HttpRouter заключается в построении большого количества префиксных деревьев. Заинтересованные могут ознакомиться: httprouter package - github.com/julienschmidt/httprouter - Go Packages.
OPTIONS & CORS
Некоторые могут захотеть изменить автоматический ответ для OPTIONS и установить некоторые заголовки ответа для адаптации к предварительным запросам CORS. Эти требования могут быть реализованы с помощью обработчика Router.GlobalOPTIONS.
router.GlobalOPTIONS = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Header.Get("Access-Control-Request-Method") != "" {
// Установить заголовки ответа CORS
header := w.Header()
header.Set("Access-Control-Allow-Methods", r.Header.Get("Allow"))
header.Set("Access-Control-Allow-Origin", "*")
}
// Адаптировать код состояния 204
w.WriteHeader(http.StatusNoContent)
})Обработчик NOT FOUND
TIP
Возможно, потребуется отключить Router.HandleMethodNotAllowed, чтобы избежать некоторых проблем.
router.NotFound = http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {
// Ваша логика
})Базовая аутентификация
package main
import (
"fmt"
"log"
"net/http"
"github.com/julienschmidt/httprouter"
)
func BasicAuth(h httprouter.Handle, requiredUser, requiredPassword string) httprouter.Handle {
return func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
// Получить базовые учётные данные
user, password, hasAuth := r.BasicAuth()
if hasAuth && user == requiredUser && password == requiredPassword {
// Делегировать запрос предоставленному обработчику
h(w, r, ps)
} else {
// Иначе запросить аутентификацию
w.Header().Set("WWW-Authenticate", "Basic realm=Restricted")
http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)
}
}
}
func Index(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
fmt.Fprint(w, "Not protected!\n")
}
func Protected(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
fmt.Fprint(w, "Protected!\n")
}
func main() {
user := "gordon"
pass := "secret!"
router := httprouter.New()
router.GET("/", Index)
router.GET("/protected/", BasicAuth(Protected, user, pass))
log.Fatal(http.ListenAndServe(":8080", router))
}