Маршрутизация
Роль маршрута в фреймворке Go Fiber заключается в привязке различных URL-адресов к обработчикам функций для поддержки обработки HTTP-запросов. Он служит входной точкой для всех запросов веб-фреймворка.
Обработчики маршрутов (Функции)
Регистрируют маршруты, привязанные к определенным HTTP-методам.
Примечание: В некоторых фреймворках обработчики маршрутов называются контроллерами, что в общем случае имеет тот же смысл — определение функции (метода) для обработки входящего HTTP-запроса.
Сигнатура функции:
// HTTP-методы
func (app *App) Get(path string, handlers ...Handler) Router
func (app *App) Head(path string, handlers ...Handler) Router
func (app *App) Post(path string, handlers ...Handler) Router
func (app *App) Put(path string, handlers ...Handler) Router
func (app *App) Delete(path string, handlers ...Handler) Router
func (app *App) Connect(path string, handlers ...Handler) Router
func (app *App) Options(path string, handlers ...Handler) Router
func (app *App) Trace(path string, handlers ...Handler) Router
func (app *App) Patch(path string, handlers ...Handler) Router
// Add allows you to specify methods as values
func (app *App) Add(method, path string, handlers ...Handler) Router
// All registers the route on all HTTP methods
// Подобно app.Use, но не привязывает префикс
func (app *App) All(path string, handlers ...Handler) Router
Пример:
// Простой обработчик GET
app.Get("/api/list", func(c *fiber.Ctx) error {
return c.SendString("Это GET-запрос!")
})
// Простой обработчик POST
app.Post("/api/register", func(c *fiber.Ctx) error {
return c.SendString("Это POST-запрос!")
})
Use используется для загрузки промежуточного программного обеспечения и перехватчиков URL-адресов. Эти маршруты сопоставляются только с началом каждого пути, например, /john
будет сопоставлен /john/doe
, /johnnnnn
и так далее.
Сигнатура пользовательской промежуточной функции:
func (app *App) Use(args ...interface{}) Router
Пример:
// Сопоставить любой запрос
app.Use(func(c *fiber.Ctx) error {
return c.Next()
})
// Сопоставить запросы, начинающиеся с /api
app.Use("/api", func(c *fiber.Ctx) error {
return c.Next()
})
// Сопоставить запросы, начинающиеся с /api или /home (поддерживает несколько префиксов)
app.Use([]string{"/api", "/home"}, func(c *fiber.Ctx) error {
return c.Next()
})
// Добавить несколько обработчиков
app.Use("/api", func(c *fiber.Ctx) error {
c.Set("X-Custom-Header", random.String(32))
return c.Next()
}, func(c *fiber.Ctx) error {
return c.Next()
})
Путь
Путь маршрута вместе с методом запроса определяет доступные конечные точки. Путь маршрута может быть строкой или шаблоном строки.
Примеры путей маршрутов на основе строк
// Этот путь маршрута будет соответствовать запросам к корневому пути, "/":
app.Get("/", func(c *fiber.Ctx) error {
return c.SendString("Корневой путь")
})
// Этот путь маршрута будет соответствовать запросам к "/about":
app.Get("/about", func(c *fiber.Ctx) error {
return c.SendString("О нас")
})
// Этот путь маршрута будет соответствовать запросам к "/random.txt":
app.Get("/random.txt", func(c *fiber.Ctx) error {
return c.SendString("Случайный.txt")
Как и в фреймворке ExpressJS, порядок объявления маршрутов имеет значение. При получении запроса маршруты проверяются в порядке их объявления.
Пожалуйста, обратите внимание: Убедитесь, что маршруты с переменными параметрами записаны после маршрутов, содержащих фиксированные части, чтобы избежать ошибочных совпадений с этими переменными частями, что может привести к непредвиденному поведению.
Параметры маршрута
Параметры маршрута являются динамическими элементами в маршруте и могут быть как именованными, так и безымянными сегментами. Эти сегменты используются для захвата значений на указанных позициях в URL. Можно использовать функцию Params для извлечения этих значений, где параметр функции представляет собой имя параметра маршрута в пути или, для безымянных параметров, это символы (*, +) и их количество.
Джокер (*) или знак плюса (+) представляют жадные параметры.
Маршруты также позволяют использовать необязательные параметры. Для именованных параметров за ними следует знак вопроса (?), в то время как знак плюса не является необязательным, и можно использовать символы джокера, чтобы представить диапазон необязательного и жадного параметра.
Пример определения маршрута с параметрами маршрута
// Параметры
app.Get("/user/:name/books/:title", func(c *fiber.Ctx) error {
fmt.Fprintf(c, "%s\n", c.Params("name"))
fmt.Fprintf(c, "%s\n", c.Params("title"))
return nil
})
// Плюс - жадный - необязательный
app.Get("/user/+", func(c *fiber.Ctx) error {
return c.SendString(c.Params("+"))
})
// Необязательный параметр
app.Get("/user/:name?", func(c *fiber.Ctx) error {
return c.SendString(c.Params("name"))
})
// Джокер - жадный - необязательный
app.Get("/user/*", func(c *fiber.Ctx) error {
return c.SendString(c.Params("*"))
})
// Этот путь маршрута будет соответствовать запросу "/v1/some/resource/name:customVerb", потому что символы параметра были экранированы
app.Get(`/v1/some/resource/name\:customVerb`, func(c *fiber.Ctx) error {
return c.SendString("Привет, команда")
})
Поскольку дефисы (-) и точки (.) интерпретируются буквально, их можно использовать вместе с параметрами маршрута для достижения полезных целей.
Все специальные символы параметров также могут быть экранированы с помощью
\
, и их значения будут игнорироваться, поэтому, если вы хотите использовать их в маршруте, рекомендуется использовать обратные кавычки ``, поскольку в документации по регулярным выражениям Go они всегда используются для обеспечения отсутствия неоднозначности, и символы экранирования не непреднамеренно влияют на шаблон регулярного выражения.
// http://localhost:3000/plantae/prunus.persica
app.Get("/plantae/:genus.:species", func(c *fiber.Ctx) error {
fmt.Fprintf(c, "%s.%s\n", c.Params("genus"), c.Params("species"))
return nil // prunus.persica
})
// http://localhost:3000/flights/LAX-SFO
app.Get("/flights/:from-:to", func(c *fiber.Ctx) error {
fmt.Fprintf(c, "%s-%s\n", c.Params("from"), c.Params("to"))
return nil // LAX-SFO
})
Наш смарт-маршрут распознает, что введенные символы параметров в данном случае должны быть частью маршрута запроса и может обрабатывать их соответственно.
// http://localhost:3000/shop/product/color:blue/size:xs
app.Get("/shop/product/color::color/size::size", func(c *fiber.Ctx) error {
fmt.Fprintf(c, "%s:%s\n", c.Params("color"), c.Params("size"))
return nil // синий:xs
})
Кроме того, маршруты могут использовать несколько параметров и несколько безымянных символов параметров последовательно, таких как символы джокера или плюса, что значительно расширяет возможности пользователей в маршрутах.
// GET /@v1
// Params: "sign" -> "@", "param" -> "v1"
app.Get("/:sign:param", handler)
// GET /api-v1
// Params: "name" -> "v1"
app.Get("/api-:name", handler)
// GET /customer/v1/cart/proxy
// Params: "*1" -> "customer/", "*2" -> "/cart"
app.Get("/*v1*/proxy", handler)
// GET /v1/brand/4/shop/blue/xs
// Params: "*1" -> "brand/4", "*2" -> "blue/xs"
app.Get("/v1/*/shop/*", handler)
Мы уже адаптировали маршрутизацию к маршрутизации Express, но пока не поддерживаем регулярные выражения, потому что они относительно медленные.
Ограничения
Когда происходит совпадение с входящим URL и путь URL разбивается на параметры, ограничения будут выполнены. Эта функция была введена в v2.37.0
и вдохновлена .NET Core.
Ограничения не предназначены для валидации параметров. Если ограничение недопустимо для значения параметра, Fiber вернет обработчик 404.
Ограничение | Пример | Соответствующие примеры |
---|---|---|
int | :id |
123456789, -123456789 |
bool | :active |
true, false |
guid | :id |
CD2C1638-1638-72D5-1638-DEADBEEF1638 |
float | :weight |
1.234, -1,001.01e8 |
minLen(value) | :username<minLen(4)> | test (не менее 4 символов) |
maxLen(value) | :filename<maxLen(8)> | MyFile (до 8 символов) |
len(length) | :filename<len(12)> | somefile.txt (12 символов) |
min(value) | :age<min(18)> | 19 (целочисленное значение должно быть не менее 18) |
max(value) | :age<max(120)> | 91 (целочисленное значение не может превышать 120) |
range(min,max) | :age<range(18,120)> | 91 (целочисленное значение должно быть не менее 18, но не может превышать 120) |
alpha | :name |
Rick (строка должна состоять из одного или нескольких буквенных символов, без учета регистра, a-z) |
datetime | :dob<datetime(2006\\-01\\-02)> | 2005-11-01 |
regex(expression) | :date<regex(\d{4}-\d{2}-\d{2})> | 2022-08-27 (должно соответствовать регулярному выражению) |
Примеры
- Одиночное ограничение
- Несколько ограничений
- Ограничение с использованием регулярного выражения
app.Get("/:test", func(c *fiber.Ctx) error {
return c.SendString(c.Params("test"))
})
// curl -X GET http://localhost:3000/12 // 12
// curl -X GET http://localhost:3000/1 // Невозможно найти GET /1
Вы можете использовать `;` для добавления нескольких ограничений.
app.Get("/:test", func(c *fiber.Ctx) error { return c.SendString(c.Params("test")) })
// curl -X GET http://localhost:3000/120000 // Невозможно найти GET /120000
// curl -X GET http://localhost:3000/1 // Невозможно найти GET /1
// curl -X GET http://localhost:3000/250 // 250
Fiber предварительно компилирует запросы с регулярными выражениями при регистрации маршрутов, поэтому нет накладных расходов на производительность для ограничений с регулярными выражениями.
```go
app.Get(`/:date`, func(c *fiber.Ctx) error {
return c.SendString(c.Params("date"))
})
// curl -X GET http://localhost:3000/125 // Невозможно найти GET /125
// curl -X GET http://localhost:3000/test // Невозможно найти GET /test
// curl -X GET http://localhost:3000/2022-08-27 // 2022-08-27
> При использовании ограничений даты-времени (`*`,`+`,`?`,`:`,`/`,``,``,`>`,';`,`(`,`)`), используйте `\\` перед специальными символами в маршруте, чтобы избежать неправильной интерпретации.
**Пример опционального параметра**
Вы также можете добавить ограничения к опциональным параметрам.
```go
app.Get("/:test?", func(c *fiber.Ctx) error {
return c.SendString(c.Params("test"))
})
// curl -X GET http://localhost:3000/42
// 42
// curl -X GET http://localhost:3000/
//
// curl -X GET http://localhost:3000/7.0
// Невозможно найти GET /7.0
Промежуточное программное обеспечение
Функции, предназначенные для обработки запросов или ответов, называются функциями промежуточного программного обеспечения (middleware functions). Next
- это функция маршрутизации Fiber, которая при вызове выполняет функцию next
, соответствующую текущему маршруту.
Пример функции промежуточного программного обеспечения
app.Use(func(c *fiber.Ctx) error {
// Установка пользовательского заголовка во всех ответах:
c.Set("X-Custom-Header", "Привет, мир")
// Переход к следующему промежуточному программному обеспечению:
return c.Next()
})
app.Get("/", func(c *fiber.Ctx) error {
return c.SendString("Привет, мир!")
})
Путь для метода Use
может быть путем монтирования (mount path) или префиксным путем (prefix path), и он ограничивает применение промежуточного программного обеспечения только к запросам с путями, начинающимися с этого пути.
Добавление ограничений маршрута во время выполнения
В связи с конструктивными и производственными соображениями динамическое добавление маршрутов после запуска приложения не поддерживается. Пожалуйста, убедитесь, что все маршруты определены до запуска приложения.
Группировка
Если у вас много конечных точек, вы можете использовать Group
для организации маршрутов.
func main() {
app := fiber.New()
api := app.Group("/api", middleware) // /api
v1 := api.Group("/v1", middleware) // /api/v1
v1.Get("/list", handler) // /api/v1/list
v1.Get("/user", handler) // /api/v1/user
v2 := api.Group("/v2", middleware) // /api/v2
v2.Get("/list", handler) // /api/v2/list
v2.Get("/user", handler) // /api/v2/user
log.Fatal(app.Listen(":3000"))
}