|
|
@@ -0,0 +1,568 @@
|
|
|
+# Fiber
|
|
|
+
|
|
|
+**Fiber** -- высокопроизводительный веб-фреймворк для приложений на **Go**.
|
|
|
+
|
|
|
+[Домашняя страница Fiber](https://gofiber.io/)
|
|
|
+[Документация](https://docs.gofiber.io/)
|
|
|
+[примеры](https://github.com/gofiber/recipes)
|
|
|
+
|
|
|
+## Простейший пример
|
|
|
+
|
|
|
+```golang
|
|
|
+package main
|
|
|
+
|
|
|
+import "github.com/gofiber/fiber/v2"
|
|
|
+
|
|
|
+func main() {
|
|
|
+ app := fiber.New()
|
|
|
+
|
|
|
+ app.Get("/", func(c *fiber.Ctx) error {
|
|
|
+ return c.SendString("Hello, World!")
|
|
|
+ })
|
|
|
+
|
|
|
+ app.Listen(":3000")
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+```bash
|
|
|
+go run server.go
|
|
|
+```
|
|
|
+
|
|
|
+По адресу `http://localhost:3000` можно посмотреть результат.
|
|
|
+
|
|
|
+## Примеры
|
|
|
+
|
|
|
+```golang
|
|
|
+// GET http://localhost:8080/hello%20world
|
|
|
+
|
|
|
+app.Get("/:value", func(c *fiber.Ctx) error {
|
|
|
+ return c.SendString("value: " + c.Params("value"))
|
|
|
+ // => Get request with value: hello world
|
|
|
+})
|
|
|
+
|
|
|
+
|
|
|
+// Опциональный параметр
|
|
|
+// GET http://localhost:3000/john
|
|
|
+app.Get("/:name?", func(c *fiber.Ctx) error {
|
|
|
+ if c.Params("name") != "" {
|
|
|
+ return c.SendString("Hello " + c.Params("name"))
|
|
|
+ // => Hello john
|
|
|
+ }
|
|
|
+ return c.SendString("Where is john?")
|
|
|
+})
|
|
|
+
|
|
|
+
|
|
|
+// Подстановочные символы
|
|
|
+// GET http://localhost:3000/api/user/john
|
|
|
+app.Get("/api/*", func(c *fiber.Ctx) error {
|
|
|
+ return c.SendString("API path: " + c.Params("*"))
|
|
|
+ // => API path: user/john
|
|
|
+})
|
|
|
+
|
|
|
+// Статические файлы
|
|
|
+app.Static("/", "./public")
|
|
|
+```
|
|
|
+
|
|
|
+## Конфигурирование
|
|
|
+
|
|
|
+```golang
|
|
|
+app := fiber.New(fiber.Config{
|
|
|
+ Prefork: true,
|
|
|
+ CaseSensitive: true,
|
|
|
+ StrictRouting: true,
|
|
|
+ ServerHeader: "Fiber",
|
|
|
+ AppName: "Test App v1.0.1",
|
|
|
+})
|
|
|
+
|
|
|
+
|
|
|
+// Работа с префорком
|
|
|
+app := fiber.New(fiber.Config{
|
|
|
+ Prefork: true,
|
|
|
+})
|
|
|
+
|
|
|
+if !fiber.IsChild() {
|
|
|
+ fmt.Println("I'm the parent process")
|
|
|
+} else {
|
|
|
+ fmt.Println("I'm a child process")
|
|
|
+}
|
|
|
+
|
|
|
+// Конфиг для статического обслуживания файлов
|
|
|
+app.Static("/", "./public", fiber.Static{
|
|
|
+ Compress: true,
|
|
|
+ ByteRange: true,
|
|
|
+ Browse: true,
|
|
|
+ Index: "john.html",
|
|
|
+ CacheDuration: 10 * time.Second,
|
|
|
+ MaxAge: 3600,
|
|
|
+})
|
|
|
+
|
|
|
+
|
|
|
+// Методы фреймворка
|
|
|
+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
|
|
|
+```
|
|
|
+
|
|
|
+## GET- POST-запросы
|
|
|
+
|
|
|
+```golang
|
|
|
+// Simple GET handler
|
|
|
+app.Get("/api/list", func(c *fiber.Ctx) error {
|
|
|
+ return c.SendString("I'm a GET request!")
|
|
|
+})
|
|
|
+
|
|
|
+// Simple POST handler
|
|
|
+app.Post("/api/register", func(c *fiber.Ctx) error {
|
|
|
+ return c.SendString("I'm a POST request!")
|
|
|
+})
|
|
|
+
|
|
|
+// Несколько маршрутов на доном обработчике
|
|
|
+// Match requests starting with /api or /home (multiple-prefix support)
|
|
|
+app.Use([]string{"/api", "/home"}, func(c *fiber.Ctx) error {
|
|
|
+ return c.Next()
|
|
|
+})
|
|
|
+```
|
|
|
+
|
|
|
+## Монтирование приложений
|
|
|
+
|
|
|
+```golang
|
|
|
+func main() {
|
|
|
+ app := fiber.New()
|
|
|
+ micro := fiber.New()
|
|
|
+ app.Mount("/john", micro) // GET /john/doe -> 200 OK
|
|
|
+
|
|
|
+ micro.Get("/doe", func(c *fiber.Ctx) error {
|
|
|
+ return c.SendStatus(fiber.StatusOK)
|
|
|
+ })
|
|
|
+
|
|
|
+ log.Fatal(app.Listen(":3000"))
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+## Группы роутов
|
|
|
+
|
|
|
+```golang
|
|
|
+func main() {
|
|
|
+ app := fiber.New()
|
|
|
+
|
|
|
+ api := app.Group("/api", handler) // /api
|
|
|
+
|
|
|
+ v1 := api.Group("/v1", handler) // /api/v1
|
|
|
+ v1.Get("/list", handler) // /api/v1/list
|
|
|
+ v1.Get("/user", handler) // /api/v1/user
|
|
|
+
|
|
|
+ v2 := api.Group("/v2", handler) // /api/v2
|
|
|
+ v2.Get("/list", handler) // /api/v2/list
|
|
|
+ v2.Get("/user", handler) // /api/v2/user
|
|
|
+
|
|
|
+ log.Fatal(app.Listen(":3000"))
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+## Ограничение числа подключений
|
|
|
+
|
|
|
+```golang
|
|
|
+func main() {
|
|
|
+ app := fiber.New()
|
|
|
+
|
|
|
+ // Выключение без контекста и с контекстом
|
|
|
+ func (app *App) Shutdown() error
|
|
|
+ func (app *App) ShutdownWithTimeout(timeout time.Duration) error
|
|
|
+ func (app *App) ShutdownWithContext(ctx context.Context) error
|
|
|
+
|
|
|
+ app.Server().MaxConnsPerIP = 1
|
|
|
+
|
|
|
+ // ...
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+## Работа с TLS
|
|
|
+
|
|
|
+```golang
|
|
|
+app.ListenTLS(":443", "./cert.pem", "./cert.key");
|
|
|
+```
|
|
|
+
|
|
|
+## работа с JSON
|
|
|
+
|
|
|
+```golang
|
|
|
+app.Get("/stack", func(c *fiber.Ctx) error {
|
|
|
+ return c.JSON(c.App().Stack())
|
|
|
+})
|
|
|
+```
|
|
|
+
|
|
|
+## РАбота с кукисами
|
|
|
+
|
|
|
+```golang
|
|
|
+app.Get("/user/delete", func(c *fiber.Ctx) error {
|
|
|
+ c.Cookie(&fiber.Cookie{
|
|
|
+ Name: "token",
|
|
|
+ // Set expiry date to the past
|
|
|
+ Expires: time.Now().Add(-(time.Hour * 2)),
|
|
|
+ HTTPOnly: true,
|
|
|
+ SameSite: "lax",
|
|
|
+ })
|
|
|
+
|
|
|
+ // ...
|
|
|
+})
|
|
|
+
|
|
|
+
|
|
|
+// Пример работы с кукисами
|
|
|
+app.Get("/", func(c *fiber.Ctx) error {
|
|
|
+ // Create cookie
|
|
|
+ cookie := new(fiber.Cookie)
|
|
|
+ cookie.Name = "john"
|
|
|
+ cookie.Value = "doe"
|
|
|
+ cookie.Expires = time.Now().Add(24 * time.Hour)
|
|
|
+
|
|
|
+ // Set cookie
|
|
|
+ c.Cookie(cookie)
|
|
|
+ // ...
|
|
|
+// Clears all cookies:
|
|
|
+ c.ClearCookie()
|
|
|
+
|
|
|
+ // Expire specific cookie by name:
|
|
|
+ c.ClearCookie("user")
|
|
|
+})
|
|
|
+```
|
|
|
+
|
|
|
+## Загрузка файлов
|
|
|
+
|
|
|
+```golang
|
|
|
+app.Get("/", func(c *fiber.Ctx) error {
|
|
|
+ return c.Download("./files/report-12345.pdf");
|
|
|
+ // => Download report-12345.pdf
|
|
|
+
|
|
|
+ return c.Download("./files/report-12345.pdf", "report.pdf");
|
|
|
+ // => Download report.pdf
|
|
|
+})
|
|
|
+```
|
|
|
+
|
|
|
+## Обработка вложений
|
|
|
+
|
|
|
+```golang
|
|
|
+app.Get("/", func(c *fiber.Ctx) error {
|
|
|
+ c.Attachment()
|
|
|
+ // => Content-Disposition: attachment
|
|
|
+
|
|
|
+ c.Attachment("./upload/images/logo.png")
|
|
|
+ // => Content-Disposition: attachment; filename="logo.png"
|
|
|
+ // => Content-Type: image/png
|
|
|
+
|
|
|
+ // ...
|
|
|
+})
|
|
|
+```
|
|
|
+
|
|
|
+## Редиректы
|
|
|
+
|
|
|
+```golang
|
|
|
+app.Get("/", func(c *fiber.Ctx) error {
|
|
|
+ return c.SendString("Home page")
|
|
|
+})
|
|
|
+app.Get("/test", func(c *fiber.Ctx) error {
|
|
|
+ c.Set("Content-Type", "text/html")
|
|
|
+ return c.SendString(`<a href="/back">Back</a>`)
|
|
|
+})
|
|
|
+
|
|
|
+app.Get("/back", func(c *fiber.Ctx) error {
|
|
|
+ return c.RedirectBack("/")
|
|
|
+})
|
|
|
+```
|
|
|
+
|
|
|
+## Пример ответа
|
|
|
+
|
|
|
+```golang
|
|
|
+app.Get("/", func(c *fiber.Ctx) error {
|
|
|
+ c.Response().BodyWriter().Write([]byte("Hello, World!"))
|
|
|
+ // => "Hello, World!"
|
|
|
+ return nil
|
|
|
+})
|
|
|
+
|
|
|
+app.Get("/", func(c *fiber.Ctx) error {
|
|
|
+ return c.Send([]byte("Hello, World!")) // => "Hello, World!"
|
|
|
+})
|
|
|
+
|
|
|
+. . .
|
|
|
+return c.SendString("Hello, World!")
|
|
|
+ // => "Hello, World!"
|
|
|
+
|
|
|
+. . .
|
|
|
+ return c.SendStream(bytes.NewReader([]byte("Hello, World!")))
|
|
|
+ // => "Hello, World!"
|
|
|
+
|
|
|
+```
|
|
|
+
|
|
|
+## Отправка статусов
|
|
|
+
|
|
|
+```golang
|
|
|
+app.Get("/not-found", func(c *fiber.Ctx) error {
|
|
|
+ return c.SendStatus(415)
|
|
|
+ // => 415 "Unsupported Media Type"
|
|
|
+
|
|
|
+ c.SendString("Hello, World!")
|
|
|
+ return c.SendStatus(415)
|
|
|
+ // => 415 "Hello, World!"
|
|
|
+})
|
|
|
+
|
|
|
+app.Get("/fiber", func(c *fiber.Ctx) error {
|
|
|
+ c.Status(fiber.StatusOK)
|
|
|
+ return nil
|
|
|
+}
|
|
|
+
|
|
|
+app.Get("/hello", func(c *fiber.Ctx) error {
|
|
|
+ return c.Status(fiber.StatusBadRequest).SendString("Bad Request")
|
|
|
+}
|
|
|
+
|
|
|
+app.Get("/world", func(c *fiber.Ctx) error {
|
|
|
+ return c.Status(fiber.StatusNotFound).SendFile("./public/gopher.png")
|
|
|
+})
|
|
|
+```
|
|
|
+
|
|
|
+## Установка заголовков
|
|
|
+
|
|
|
+```golang
|
|
|
+app.Get("/", func(c *fiber.Ctx) error {
|
|
|
+ c.Set("Content-Type", "text/plain")
|
|
|
+ // => "Content-type: text/plain"
|
|
|
+
|
|
|
+ // ...
|
|
|
+})
|
|
|
+```
|
|
|
+
|
|
|
+## Обработка XML
|
|
|
+
|
|
|
+```golang
|
|
|
+type SomeStruct struct {
|
|
|
+ XMLName xml.Name `xml:"Fiber"`
|
|
|
+ Name string `xml:"Name"`
|
|
|
+ Age uint8 `xml:"Age"`
|
|
|
+}
|
|
|
+
|
|
|
+app.Get("/", func(c *fiber.Ctx) error {
|
|
|
+ // Create data struct:
|
|
|
+ data := SomeStruct{
|
|
|
+ Name: "Grame",
|
|
|
+ Age: 20,
|
|
|
+ }
|
|
|
+
|
|
|
+ return c.XML(data)
|
|
|
+ // <Fiber>
|
|
|
+ // <Name>Grame</Name>
|
|
|
+ // <Age>20</Age>
|
|
|
+ // </Fiber>
|
|
|
+})
|
|
|
+```
|
|
|
+
|
|
|
+## Запросы с помощью клиента Fiber (например, для прокси сервера)
|
|
|
+
|
|
|
+```golang
|
|
|
+// Get something
|
|
|
+func getSomething(c *fiber.Ctx) (err error) {
|
|
|
+ agent := fiber.Get("<URL>")
|
|
|
+ statusCode, body, errs := agent.Bytes()
|
|
|
+ if len(errs) > 0 {
|
|
|
+ return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
|
|
+ "errs": errs,
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+ var something fiber.Map
|
|
|
+ err = json.Unmarshal(body, &something)
|
|
|
+ if err != nil {
|
|
|
+ return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
|
|
+ "err": err,
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+ return c.Status(statusCode).JSON(something)
|
|
|
+}
|
|
|
+
|
|
|
+// Post something
|
|
|
+func createSomething(c *fiber.Ctx) (err error) {
|
|
|
+ agent := fiber.Post("<URL>")
|
|
|
+ agent.Body(c.Body()) // set body received by request
|
|
|
+ statusCode, body, errs := agent.Bytes()
|
|
|
+ if len(errs) > 0 {
|
|
|
+ return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
|
|
+ "errs": errs,
|
|
|
+ })
|
|
|
+ }
|
|
|
+ agent.ConnectionClose()
|
|
|
+ // pass status code and body received by the proxy
|
|
|
+ return c.Status(statusCode).Send(body)
|
|
|
+}
|
|
|
+
|
|
|
+// Авторизация с агентом
|
|
|
+func (a *Agent) BasicAuth(username, password string) *Agent
|
|
|
+func (a *Agent) BasicAuthBytes(username, password []byte) *Agent
|
|
|
+```
|
|
|
+
|
|
|
+## Логгер
|
|
|
+
|
|
|
+```golang
|
|
|
+import "github.com/gofiber/fiber/v2/log"
|
|
|
+
|
|
|
+log.SetLevel(log.LevelInfo)
|
|
|
+
|
|
|
+log.Info("info")
|
|
|
+log.Warn("warn")
|
|
|
+```
|
|
|
+
|
|
|
+## Мидэлвейр (несколько примеров)
|
|
|
+
|
|
|
+```golang
|
|
|
+package main
|
|
|
+
|
|
|
+import (
|
|
|
+ "fmt"
|
|
|
+ "net/http"
|
|
|
+
|
|
|
+ "github.com/gofiber/fiber/v2"
|
|
|
+ "github.com/gofiber/fiber/v2/middleware/adaptor"
|
|
|
+)
|
|
|
+
|
|
|
+func main() {
|
|
|
+ // New fiber app
|
|
|
+ app := fiber.New()
|
|
|
+
|
|
|
+ // http.Handler -> fiber.Handler
|
|
|
+ app.Get("/", adaptor.HTTPHandler(handler(greet)))
|
|
|
+
|
|
|
+ // http.HandlerFunc -> fiber.Handler
|
|
|
+ app.Get("/func", adaptor.HTTPHandlerFunc(greet))
|
|
|
+
|
|
|
+ // Listen on port 3000
|
|
|
+ app.Listen(":3000")
|
|
|
+}
|
|
|
+
|
|
|
+func handler(f http.HandlerFunc) http.Handler {
|
|
|
+ return http.HandlerFunc(f)
|
|
|
+}
|
|
|
+
|
|
|
+func greet(w http.ResponseWriter, r *http.Request) {
|
|
|
+ fmt.Fprint(w, "Hello World!")
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+Пример ниже можно использовать совместно с `go-app` (* WebApp *)
|
|
|
+
|
|
|
+```golang
|
|
|
+package main
|
|
|
+
|
|
|
+import (
|
|
|
+ "net/http"
|
|
|
+
|
|
|
+ "github.com/gofiber/fiber/v2"
|
|
|
+ "github.com/gofiber/fiber/v2/middleware/adaptor"
|
|
|
+)
|
|
|
+
|
|
|
+func main() {
|
|
|
+ // fiber.Handler -> http.Handler
|
|
|
+ http.Handle("/", adaptor.FiberHandler(greet))
|
|
|
+
|
|
|
+ // fiber.Handler -> http.HandlerFunc
|
|
|
+ http.HandleFunc("/func", adaptor.FiberHandlerFunc(greet))
|
|
|
+
|
|
|
+ // Listen on port 3000
|
|
|
+ http.ListenAndServe(":3000", nil)
|
|
|
+}
|
|
|
+
|
|
|
+func greet(c *fiber.Ctx) error {
|
|
|
+ return c.SendString("Hello World!")
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+## Сквозное сжатие (мидлвейр)
|
|
|
+
|
|
|
+```golang
|
|
|
+import (
|
|
|
+ "github.com/gofiber/fiber/v2"
|
|
|
+ "github.com/gofiber/fiber/v2/middleware/compress"
|
|
|
+)
|
|
|
+
|
|
|
+// Initialize default config
|
|
|
+app.Use(compress.New())
|
|
|
+
|
|
|
+// Or extend your config for customization
|
|
|
+app.Use(compress.New(compress.Config{
|
|
|
+ Level: compress.LevelBestSpeed, // 1
|
|
|
+}))
|
|
|
+
|
|
|
+// Skip middleware for specific routes
|
|
|
+app.Use(compress.New(compress.Config{
|
|
|
+ Next: func(c *fiber.Ctx) bool {
|
|
|
+ return c.Path() == "/dont_compress"
|
|
|
+ },
|
|
|
+ Level: compress.LevelBestSpeed, // 1
|
|
|
+}))
|
|
|
+```
|
|
|
+
|
|
|
+## Разрешение CORS (мидлвейер)
|
|
|
+
|
|
|
+```golang
|
|
|
+// Initialize default config
|
|
|
+app.Use(cors.New())
|
|
|
+
|
|
|
+// Or extend your config for customization
|
|
|
+app.Use(cors.New(cors.Config{
|
|
|
+ AllowOrigins: "https://gofiber.io, https://gofiber.net",
|
|
|
+ AllowHeaders: "Origin, Content-Type, Accept",
|
|
|
+}))
|
|
|
+```
|
|
|
+
|
|
|
+## обработка шаблонов
|
|
|
+
|
|
|
+```golang
|
|
|
+app.Get("/", func(c *fiber.Ctx) error {
|
|
|
+ return c.Render("index", fiber.Map{
|
|
|
+ "hello": "world",
|
|
|
+ });
|
|
|
+})
|
|
|
+```
|
|
|
+
|
|
|
+Поддерживаются шаблоны:
|
|
|
+
|
|
|
+- ace
|
|
|
+- amber
|
|
|
+- django (python)
|
|
|
+- handlebars
|
|
|
+- html
|
|
|
+- jet
|
|
|
+- mustache
|
|
|
+- pug
|
|
|
+- slim
|
|
|
+
|
|
|
+```golang
|
|
|
+package main
|
|
|
+
|
|
|
+import (
|
|
|
+ "log"
|
|
|
+ "github.com/gofiber/fiber/v2"
|
|
|
+ "github.com/gofiber/template/html/v2"
|
|
|
+)
|
|
|
+
|
|
|
+func main() {
|
|
|
+ // Initialize standard Go html template engine
|
|
|
+ engine := html.New("./views", ".html")
|
|
|
+ // If you want other engine, just replace with following
|
|
|
+ // Create a new engine with django
|
|
|
+ // engine := django.New("./views", ".django")
|
|
|
+
|
|
|
+ app := fiber.New(fiber.Config{
|
|
|
+ Views: engine,
|
|
|
+ })
|
|
|
+ app.Get("/", func(c *fiber.Ctx) error {
|
|
|
+ // Render index template
|
|
|
+ return c.Render("index", fiber.Map{
|
|
|
+ "Title": "Hello, World!",
|
|
|
+ })
|
|
|
+ })
|
|
|
+
|
|
|
+ log.Fatal(app.Listen(":3000"))
|
|
|
+}
|
|
|
+```
|