1 В избранное 0 Ответвления 0

OSCHINA-MIRROR/mirrors-elton

Клонировать/Скачать
middlewares.md 31 КБ
Копировать Редактировать Web IDE Исходные данные Просмотреть построчно История
Отправлено 04.06.2025 23:59 7f2703a
description
Различные часто используемые middleware-компоненты

Middleware- basic auth Базовая аутентификация HTTP, рекомендуется использовать только для внутренних систем управления

  • body parser Мидлвар для парсинга данных запроса, поддерживает два типа данных: application/json и application/x-www-form-urlencoded
  • cache Модуль кэширования HTTP, кэширует данные на основе заголовка Cache-Control и поддерживает кэширование данных после сжатия с использованием br или gzip
  • compress Мидлвар для сжатия данных, по умолчанию поддерживает только gzip. Если требуется поддержка дополнительных методов сжатия, таких как brotli, snappy, zstd и lz4, можно использовать elton-compress, а также добавлять соответствующие методы сжатия по необходимости
  • concurrent limiter Мидлвар для ограничения количиства одновременных запросов на основе заданных параметров, полезен для предотвращения повторных подач заявок или ограничения частоты подач заявок, например, при подаче заказов
  • error handler Мидлвар для обработки ошибок, преобразующий ошибки в соответствующие данные ответа, такие как HTTP-коды ошибок (4xx, 5xx) и типы ошибок. Рекомендуется использовать собственные объекты ошибок проекта для генерации соответствующих данных ответа
  • etag Мидлвар для генерации ETag для HTTP-ответа
  • fresh Проверяет, является ли HTTP-запрос неизмененным (Not Modified)
  • json pickercom/vicanso/elton-json-picker) Мидлвар для выбора определенных полей из JSON-ответа
  • jwt Мидлвар для работы с JWT
  • logger Мидлвар для логирования HTTP-запросов, поддерживает получение информации из заголовков запроса и ответа
  • proxy Мидлвар для проксирования запросов на другие сервисы
  • recover Мидлвар для перехвата паники (panic) в программе, предотвращающий её падение
  • renderer Мидлвар для рендеринга шаблонов, преобразующий шаблоны в HTML
  • responder Мидлвар для обработки ответов, преобразующий Context.Body (interface{}) в соответствующие данные JSON и выводящий их. Если система использует XML для вывода данных ответа, можно использовать этот мидлвар для преобразования interface{} в XML
  • response-size-limiter Мидлвар для ограничения размера ответа, ограничивающий максимальный размер данных ответа
  • router-concurrent-limiter Мидлвар для ограничения количества одновременных запросов для маршрута
  • session Мидлвар для работы с сессиями, по умолчанию поддерживает хранение в памяти, но можно настроить хранение в Redis или других базах данных - stats Мидлвар для статистики обработки запросов, включая время обработки, коды ответов, размеры данных ответа и количество подключений.
  • static serve Мидлвар для обработки статических файлов, по умолчанию поддерживает чтение статических файлов из директории или реализацию соответствующих интерфейсов для класса StaticFile, чтение файлов из packr или баз данных (например, MongoDB).
  • tracker Мидлвар для добавления трекинговых логов в POST, PUT и другие методы отправки данных. Этот мидлвар выводит QueryString, Params и часть RequestBody, а также маскирует определенные поля символами "***", чтобы избежать вывода конфиденциальной информации.

Базовая аутентификацияHTTP базовая аутентификация — это middleware, предоставляющий простой способ аутентификации. Рекомендуется использовать только для внутренних систем управления.

Пример

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.

NewDefaultBodyParser

Создает стандартный парсер тела запроса, который включает обработку gzip и json. Сначала проверяется, является ли Content-Encoding gzip. Если да, то сначала происходит декомпрессия, а затем проверяется, является ли данные json.

e.Use(middleware.NewDefaultBodyParser())

NewGzipDecoder

Создает декодер для данных, сжатых с помощью gzip.

conf := middleware.BodyParserConfig{}
conf.AddDecoder(middleware.NewGzipDecoder())
e.Use(middleware.NewBodyParser(conf))

NewJSONDecoder## кэш

Кэш-мидлваре, для запросов 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 и другие.

Compressor

Для реализации собственного метода сжатия необходимо реализовать три метода:

  • 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 Значение ключа из параметров маршрута
  • Другие ключи берутся из HTTP-тела запроса (только JSON)

Пример

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

Обработчик ошибокОбработчик ошибок, который преобразует ошибки в JSON или текстовые ответы об ошибках. Рекомендуется использовать собственные типы ошибок в бизнес-логике, а также использовать middleware для обработки ошибок и вывода соответствующих сообщений об ошибках. Это позволяет легко собирать статистику по непредопределённым ошибкам и улучшать систему.Пример

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

etag

Создаёт 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)
	}
}

fresh

Проверяет заголовки 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)
	}
}

loggerMiddleware для логирования, который поддерживает получение информации из заголовков запроса и ответа. Метки в логах обозначаются как {}, поддерживаемые метки включают:

  • host запроса хост
  • method запроса метод
  • path запроса путь
  • proto запроса протокол
  • query запроса сырой query
  • remote запроса удалённый адрес
  • real-ip клиента реальный IP
  • client-ip IP клиента, отличие от real-ip в том, что проверяется на публичность IP
  • scheme HTTP или HTTPS
  • uri полный запросный URI
  • referer запроса referer
  • userAgent запроса user agent
  • when текущее время в формате RFC1123 с временной зоной
  • when-iso текущее время в формате RFC3339
  • when-utc-iso текущее время UTC в формате ISO
  • when-unix текущее время в формате Unix (секунды)
  • when-iso-ms текущее время в формате RFC3339 (миллисекунды)
  • when-utc-iso-ms текущее время UTC в формате ISO (миллисекунды)
  • size размер ответа (байты)
  • size-human размер ответа, отформатированный в KB/MB (с округлением до 1024)
  • status код состояния
  • latency время ответа
  • latency-ms время ответа (миллисекунды)
  • ~cookie указывает на получение значения cookie, должно начинаться с ~, за которым следует ключ cookie
  • payload-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)
	}
}

proxy

Прокси-_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)
	}
}

recover

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 )

Вы можете оставить комментарий после Вход в систему

1
https://api.gitlife.ru/oschina-mirror/mirrors-elton.git
git@api.gitlife.ru:oschina-mirror/mirrors-elton.git
oschina-mirror
mirrors-elton
mirrors-elton
master