lesson05.md 12 KB

Fiber

Fiber -- высокопроизводительный веб-фреймворк для приложений на Go.

Домашняя страница Fiber Документация примеры

Простейший пример

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")
}
go run server.go

По адресу http://localhost:3000 можно посмотреть результат.

Примеры

// 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")

Конфигурирование

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-запросы

// 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()
})

Монтирование приложений

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"))
}

Группы роутов

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"))
}

Ограничение числа подключений

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

app.ListenTLS(":443", "./cert.pem", "./cert.key");

работа с JSON

app.Get("/stack", func(c *fiber.Ctx) error {
  return c.JSON(c.App().Stack())
})

Работа с кукисами

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")
})

Загрузка файлов

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
})

Обработка вложений

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

  // ...
})

Редиректы

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("/")
})

Пример ответа

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!"

Отправка статусов

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")
})

Установка заголовков

app.Get("/", func(c *fiber.Ctx) error {
  c.Set("Content-Type", "text/plain")
  // => "Content-type: text/plain"

  // ...
})

Обработка XML

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 (например, для прокси сервера)

// 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

Логгер

import "github.com/gofiber/fiber/v2/log"

log.SetLevel(log.LevelInfo)

log.Info("info")
log.Warn("warn")

Мидэлвейр (несколько примеров)

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 *)

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!")
}

Сквозное сжатие (мидлвейр)

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 (мидлвейер)

// 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",
}))

обработка шаблонов

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

    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"))
    }