description |
---|
Различные часто используемые middleware-компоненты |
application/json
и application/x-www-form-urlencoded
Cache-Control
и поддерживает кэширование данных после сжатия с использованием br или gzipContext.Body
(interface{}) в соответствующие данные JSON и выводящий их. Если система использует XML для вывода данных ответа, можно использовать этот мидлвар для преобразования interface{} в XMLПример
package main
import (
"bytes"
"github.com/vicanso/elton"
"github.com/vicanso/elton/middleware"
"github.com/vicanso/hes"
)
func main() {
e := elton.New()
e.Use(middleware.NewBasicAuth(middleware.BasicAuthConfig{
Validate: func(account, pwd string, c *elton.Context) (bool, error) {
if account == "tree.xie" && pwd == "password" {
return true, nil
}
if account == "n" {
return false, hes.New("учетная запись недействительна")
}
return false, nil
},
}))
e.GET("/", func(c *elton.Context) (err error) {
c.BodyBuffer = bytes.NewBufferString("hello world")
return
})
err := e.ListenAndServe(":3000")
if err != nil {
panic(err)
}
}
Парсер HTTP запроса для обработки данных, полученных в теле запроса. Поддерживает отправку данных в форматах json
и form
. Можно добавлять различные декодеры для поддержки различных типов данных, таких как декомпрессия данных, отправленных в формате gzip
.
Создает стандартный парсер тела запроса, который включает обработку gzip
и json
. Сначала проверяется, является ли Content-Encoding
gzip
. Если да, то сначала происходит декомпрессия, а затем проверяется, является ли данные json
.
e.Use(middleware.NewDefaultBodyParser())
Создает декодер для данных, сжатых с помощью gzip
.
conf := middleware.BodyParserConfig{}
conf.AddDecoder(middleware.NewGzipDecoder())
e.Use(middleware.NewBodyParser(conf))
Кэш-мидлваре, для запросов GET
и HEAD
определяет, можно ли кэшировать запрос на основе заголовка Cache-Control
. Если запрос можно кэшировать, данные кэшируются в хранилище, и при повторном запросе данные извлекаются из кэша. Кэшированные данные могут быть сжаты перед кэшированием, и при ответе клиенту автоматически возвращаются сжатые или несжатые данные. Важно отметить, что все современные браузеры поддерживают сжатие brotli, но браузеры устанавливают поддержку brotli только в режиме HTTPS, поэтому если сервис работает только в режиме HTTP, рекомендуется использовать gzip для сжатия.- Ключ кэширования запроса по умолчанию — это Method
+ RequestURI
.
fetch
указывает на запрос без кэша, после получения ответа проверяется, можно ли кэшировать ответ. Если можно, кэшируется ответ (состояние: hit
, данные: заголовок ответа и тело ответа). Если нельзя, кэшируется пустое значение (состояние: hit-for-pass
, данные: пустое).hit-for-pass
указывает на запрос, который имеет кэшированный ответ, но этот кэшированный ответ указывает на то, что запрос не может быть кэширован.hit
указывает на запрос, который имеет кэшированный ответ, и кэшированные данные могут быть использованы, и ответ возвращается клиенту из кэша.package main
import (
"bytes"
"github.com/vicanso/elton"
"github.com/vicanso/elton/middleware"
)
func main() {
e := elton.New()
// Использование redis для кэширования
e.Use(middleware.NewDefaultCache(redisStore))
e.GET("/", func(c *elton.Context) (err error) {
c.CacheMaxAge(time.Minute)
c.BodyBuffer = bytes.NewBuffer(c.RequestBody)
return
})
err := e.ListenAndServe(":3000")
if err != nil {
panic(err)
}
}
Мидлваре для сжатия ответов, которое может сжимать определенные типы данных и данные определенной длины. По умолчанию поддерживает сжатие gzip
и brotli
, но можно расширить список поддерживаемых методов сжатия, например, lz4
, zstd
и другие.
Для реализации собственного метода сжатия необходимо реализовать три метода:
Accept
проверяет, поддерживает ли метод сжатия текущий запрос, на основе заголовков запроса и размера данных.Compress
метод сжатия данных.Pipe
метод обработки данных.Пример
package main
import (
"bytes"
"github.com/vicanso/elton"
"github.com/vicanso/elton/middleware"
)
func main() {
e := elton.New()
e.Use(middleware.NewDefaultCompress())
e.Use(middleware.NewDefaultResponder())
e.GET("/", func(c *elton.Context) error {
b := new(bytes.Buffer)
for i := 0; i < 1000; i++ {
b.WriteString("Hello, World!")
}
c.Body = &struct {
Message string
}{
b.String(),
}
return nil
})
err := e.ListenAndServe(":3000")
if err != nil {
panic(err)
}
}
Глобальный лимитер конкурирующих запросов, который можно использовать для контроля количества параллельных запросов приложения.Пример
package main
import (
"bytes"
"sync"
"time"
"github.com/vicanso/elton"
"github.com/vicanso/elton/middleware"
)
func main() {
e := elton.New()
e.Use(middleware.NewGlobalConcurrentLimiter(middleware.GlobalConcurrentLimiterConfig{
Max: 1000,
}))
e.POST("/login", func(c *elton.Context) (err error) {
time.Sleep(3 * time.Second)
c.BodyBuffer = bytes.NewBufferString("hello world")
return
})
err := e.ListenAndServe(":3000")
if err != nil {
panic(err)
}
}
Лимитер конкурирующих запросов, который позволяет ограничивать количество одновременных запросов, используя параметры запроса, такие как IP, поля запроса или тело запроса. Основные ключи:
:ip
Реальный IP клиентаh:key
Значение ключа из HTTP-заголовковq:key
Значение ключа из HTTP-запросаp:key
Значение ключа из параметров маршрутаПример
package main
import (
"bytes"
"sync"
"time"
"github.com/vicanso/elton"
"github.com/vicanso/elton/middleware"
)
func main() {
e := elton.New()
m := new(sync.Map)
limit := middleware.NewConcurrentLimiter(middleware.ConcurrentLimiterConfig{
Keys: []string{
":ip",
"h:X-Token",
"q:type",
"p:id",
"account",
},
Lock: func(key string, c *elton.Context) (success bool, unlock func(), err error) {
_, loaded := m.LoadOrStore(key, true)
// ключ не существует
if !loaded {
success = true
unlock = func() {
m.Delete(key)
}
}
return
},
})
e.POST("/login", limit, func(c *elton.Context) (err error) {
time.Sleep(3 * time.Second)
c.BodyBuffer = bytes.NewBufferString("hello world")
return
})
package main
import (
"errors"
"github.com/vicanso/elton"
"github.com/vicanso/elton/middleware"
)
func main() {
e := elton.New()
e.Use(middleware.NewDefaultError())
e.GET("/", func(c *elton.Context) (err error) {
err = errors.New("abcd")
return
})
err := e.ListenAndServe(":3000")
if err != nil {
panic(err)
}
}
Создаёт HTTP-заголовок ETag на основе данных в ответе. Для этого необходимо использовать middleware Responder для преобразования ответа в буфер или установки BodyBuffer.
Пример
package main
import (
"bytes"
"github.com/vicanso/elton"
"github.com/vicanso/elton/middleware"
)
func main() {
e := elton.New()
e.Use(middleware.NewDefaultETag())
e.GET("/", func(c *elton.Context) (err error) {
c.BodyBuffer = bytes.NewBufferString("abcd")
return
})
err := e.ListenAndServe(":3000")
if err != nil {
panic(err)
}
}
Проверяет заголовки HTTP-запроса и ответа для определения, был ли ресурс изменён (304 Not Modified).
Пример
package main
import (
"bytes"
"github.com/vicanso/elton"
"github.com/vicanso/elton/middleware"
)
func main() {
e := elton.New()
e.Use(middleware.NewDefaultFresh())
e.Use(middleware.NewDefaultETag())
e.GET("/", func(c *elton.Context) (err error) {
c.BodyBuffer = bytes.NewBufferString("abcd")
return
})
err := e.ListenAndServe(":3000")
if err != nil {
panic(err)
}
}
host
запроса хостmethod
запроса методpath
запроса путьproto
запроса протоколquery
запроса сырой queryremote
запроса удалённый адресreal-ip
клиента реальный IPclient-ip
IP клиента, отличие от real-ip в том, что проверяется на публичность IPscheme
HTTP или HTTPSuri
полный запросный URIreferer
запроса refereruserAgent
запроса user agentwhen
текущее время в формате RFC1123 с временной зонойwhen-iso
текущее время в формате RFC3339when-utc-iso
текущее время UTC в формате ISOwhen-unix
текущее время в формате Unix (секунды)when-iso-ms
текущее время в формате RFC3339 (миллисекунды)when-utc-iso-ms
текущее время UTC в формате ISO (миллисекунды)size
размер ответа (байты)size-human
размер ответа, отформатированный в KB/MB (с округлением до 1024)status
код состоянияlatency
время ответаlatency-ms
время ответа (миллисекунды)~cookie
указывает на получение значения cookie, должно начинаться с ~, за которым следует ключ cookiepayload-size
размер отправленных данных (байты)payload-size-human
размер отправленных данных, отформатированный в KB/MB (с округлением до 1024)>header
указывает на получение значения заголовка запроса, должно начинаться с >, за которым следует ключ заголовка- <header
указывает на получение значения заголовка ответа, должно начинаться с <, за которым следует ключ заголовка:key
указывает на получение значения контекста, должно начинаться с :, за которым следует ключ$key
указывает на получение значения переменной окружения, должно начинаться с $, за которым следует ключПредопределены четыре формата логирования (рекомендуется использовать с настройкой собственного шаблона логирования):
LoggerCombined
: {remote} {when-iso} "{method} {uri} {proto}" {status} {size-human} "{referer}" "{userAgent}"
LoggerCommon
: {remote} {when-iso} "{method} {uri} {proto}" {status} {size-human}
LoggerShort
: {remote} {method} {uri} {proto} {status} {size-human} - {latency-ms} ms
LoggerTiny
: {method} {url} {status} {size-human} - {latency-ms} ms
Пример
package main
import (
"fmt"
"github.com/vicanso/elton"
"github.com/vicanso/elton/middleware"
)
func main() {
e := elton.New()
// обработка паники
e.Use(middleware.NewRecover())
e.Use(middleware.NewLogger(middleware.LoggerConfig{
Format: middleware.LoggerCombined,
OnLog: func(str string, _ *elton.Context) {
fmt.Println(str)
},
}))
// преобразование ответных данных в JSON
e.Use(middleware.NewDefaultResponder())
e.GET("/", func(c *elton.Context) error {
c.Body = &struct {
Message string `json:"message,omitempty"`
}{
Message: "Hello, World!",
}
return nil
})
err := e.ListenAndServe(":3000")
if err != nil {
panic(err)
}
}
Прокси-_MIDDLEWARE, который позволяет перенаправлять определенные запросы на другие сервисы и перезаписывать URL.
Пример
package main
import (
"net/url"
"github.com/vicanso/elton"
"github.com/vicanso/elton/middleware"
)
func main() {
e := elton.New()
target, _ := url.Parse("https://www.baidu.com")
e.GET("/*", middleware.NewProxy(middleware.ProxyConfig{
// функция, вызываемая при завершении прокси
Done: func(c *elton.Context) {
},
// перезапись URL запроса
Rewrites: []string{
"/api/*:/$1",
},
Target: target,
// изменение хоста запроса
Host: "www.baidu.com",
}))
err := e.ListenAndServe(":3000")
if err != nil {
panic(err)
}
}
Middleware восстановления, используемый для перехвата различных исключений паники, чтобы избежать неожиданного завершения программы. Рекомендуется создать собственный middleware восстановления, чтобы при получении таких исключений отправлять уведомление и выполнять грациозное перезапуск.
Пример
package main
import (
"errors"
"github.com/vicanso/elton"
"github.com/vicanso/elton/middleware"
)
``````## рендерер
Мидлвар для рендера шаблонов, используется для преобразования различных шаблонов в HTML-вывод. По умолчанию поддерживаются шаблоны `html` и `tmpl`, для которых используется модуль `html/template`.
```go
package main
import (
"errors"
"github.com/vicanso/elton"
"github.com/vicanso/elton/middleware"
)
func main() {
e := elton.New()
e.Use(middleware.NewRenderer(middleware.RendererConfig{}))
e.GET("/", func(c *elton.Context) (err error) {
c.Body = middleware.RenderData{
File: "index.html",
}
})
err := e.ListenAndServe(":3000")
if err != nil {
panic(err)
}
}
Используется для преобразования тела запроса в соответствующие байтовые данные и установки заголовков ответа. По умолчанию структуры (map) преобразуются в JSON. Для различных приложений можно указать собственные функции Marshal и ContentType для создания пользовательских ответов.
ResponderConfig.Marshal
- пользовательская функция Marshal, по умолчанию json.Marshal
ResponderConfig.ContentType
- пользовательский тип контента, по умолчанию application/json; charset=utf-8
Пример
package main
import (
"github.com/vicanso/elton"
"github.com/vicanso/elton/middleware"
)
func main() {
e := elton.New()
e.Use(middleware.NewDefaultResponder())
// {"name":"tree.xie","id":123}
e.GET("/", func(c *elton.Context) (err error) {
c.Body = &struct {
Name string `json:"name"`
ID int `json:"id"`
}{
"tree.xie",
123,
}
return
})
err := e.ListenAndServe(":3000")
if err != nil {
panic(err)
}
}
**Пример**
```go
package main
import (
"bytes"
"time"
"github.com/vicanso/elton"
"github.com/vicanso/elton/middleware"
)
func main() {
e := elton.New()
e.Use(middleware.NewResponseSizeLimiter(middleware.ResponseSizeLimiterConfig{
// 1MB
MaxSize: 1024 * 1024,
}))
e.GET("/users/me", func(c *elton.Context) (err error) {
time.Sleep(time.Second)
c.BodyBuffer = bytes.NewBufferString(`{
"account": "tree",
"name": "tree.xie"
}`)
return nil
})
err := e.ListenAndServe(":3000")
if err != nil {
panic(err)
}
}
Мидлвар для ограничения параллельного доступа к маршруту, позволяет указать максимальное количество одновременных запросов для каждого маршрута. Это используется для предотвращения перегрузки системы из-за слишком большого параллельного доступа к определенному интерфейсу.
Пример
package main
import (
"github.com/vicanso/elton"
"github.com/vicanso/elton/middleware"
)
func main() {
e := elton.New()
e.Use(middleware.NewRouterConcurrentLimiter(middleware.RouterConcurrentLimiterConfig{
Limit: 10,
}))
e.GET("/", func(c *elton.Context) (err error) {
return
})
err := e.ListenAndServe(":3000")
if err != nil {
panic(err)
}
}
Пример
package main
import (
"bytes"
"time"
"github.com/vicanso/elton"
"github.com/vicanso/elton/middleware"
)
func main() {
e := elton.New()
e.Use(middleware.NewRCL(middleware.RCLConfig{
Limiter: middleware.NewLocalLimiter(map[string]uint32{
"GET /users/me": 2,
}),
}))
e.GET("/users/me", func(c *elton.Context) (err error) {
time.Sleep(time.Second)
c.BodyBuffer = bytes.NewBufferString(`{
"account": "tree",
"name": "tree.xie"
}`)
return nil
})
err := e.ListenAndServe(":3000")
if err != nil {
panic(err)
}
}
```## статистика
HTTP запросов статистический middleware, который позволяет записывать различные статистические данные HTTP запросов в базу данных, такую как InfluxDB, для оптимизации производительности и мониторинга.
**Пример**
```go
package main
import (
"bytes"
"encoding/json"
"fmt"
"github.com/vicanso/elton"
"github.com/vicanso/elton/middleware"
)
func main() {
e := elton.New()
e.Use(middleware.NewStats(middleware.StatsConfig{
OnStats: func(info *middleware.StatsInfo, _ *elton.Context) {
buf, _ := json.Marshal(info)
fmt.Println(string(buf))
},
}))
e.GET("/", func(c *elton.Context) (err error) {
c.BodyBuffer = bytes.NewBufferString("abcd")
return
})
err := e.ListenAndServe(":3000")
if err != nil {
panic(err)
}
}
Middleware для обслуживания статических файлов, который по умолчанию поддерживает доступ к файлам через директорию. В зависимости от потребностей можно реализовать различные способы хранения, такие как packr
для упаковки или MongoDB для хранения.
Пример
package main
import (
"time"
"github.com/vicanso/elton"
"github.com/vicanso/elton/middleware"
)
func main() {
e := elton.New()
sf := new(middleware.FS)
// маршрут для статических файлов
e.GET("/*", middleware.NewStaticServe(sf, middleware.StaticServeConfig{
Path: "/tmp",
// клиентская кэширование на год
MaxAge: 365 * 24 * time.Hour,
// кэширование сервера на час
SMaxAge: time.Hour,
DenyQueryString: true,
DisableLastModified: true,
// если используется packr, он не поддерживает Stat, поэтому нужно использовать сильный ETag
EnableStrongETag: true,
}))
err := e.ListenAndServe(":3000")
if err != nil {
panic(err)
}
}
Использование Packr для упаковки фронтенда приложения, и предоставление статических файлов через статический сервер:Пример
package main
``````md
## трекер
Используется для добавления трекинговых логов при отправке клиентом запросов. Может выводить информацию о запросе, теле запроса и параметрах, а также настраивать регулярное выражение для маскировки ключевых данных звездочками.
**Пример**
```go
package main
import (
"bytes"
"encoding/json"
"fmt"
"github.com/vicanso/elton"
"github.com/vicanso/elton/middleware"
)
func main() {
e := elton.New()
loginTracker := middleware.NewTracker(middleware.TrackerConfig{
OnTrack: func(info *middleware.TrackerInfo, _ *elton.Context) {
buf, _ := json.Marshal(info)
fmt.Println(string(buf))
},
})
e.Use(func(c *elton.Context) error {
c.RequestBody = []byte(`{
"account": "tree.xie",
"password": "123456"
}`)
return c.Next()
})
e.POST("/user/login", loginTracker, func(c *elton.Context) (err error) {
c.SetHeader(elton.HeaderContentType, elton.MIMEApplicationJSON)
c.BodyBuffer = bytes.NewBuffer(c.RequestBody)
return
})
}
err := e.ListenAndServe(":3000")
if err != nil {
panic(err)
}
}
```
Вы можете оставить комментарий после Вход в систему
Неприемлемый контент может быть отображен здесь и не будет показан на странице. Вы можете проверить и изменить его с помощью соответствующей функции редактирования.
Если вы подтверждаете, что содержание не содержит непристойной лексики/перенаправления на рекламу/насилия/вульгарной порнографии/нарушений/пиратства/ложного/незначительного или незаконного контента, связанного с национальными законами и предписаниями, вы можете нажать «Отправить» для подачи апелляции, и мы обработаем ее как можно скорее.
Опубликовать ( 0 )