EchoMiddleCoding

Как определить и зарегистрировать middleware в Echo?

Middleware в Echo — функция (echo.HandlerFunc) echo.HandlerFunc; регистрируется глобально через e.Use(), на группу через group.Use() или на конкретный маршрут третьим аргументом.

Middleware в Echo: определение и регистрация

Middleware в Echo — это функция с сигнатурой func(echo.HandlerFunc) echo.HandlerFunc. Она получает следующий хендлер в цепочке и возвращает новый хендлер, оборачивающий его логикой до/после.

Написание своего middleware

package middleware

import (
	"time"

	"github.com/labstack/echo/v4"
)

// RequestTimer измеряет время выполнения запроса
func RequestTimer() echo.MiddlewareFunc {
	return func(next echo.HandlerFunc) echo.HandlerFunc {
		return func(c echo.Context) error {
			start := time.Now()

			// Логика "до"
			err := next(c) // вызов следующего хендлера

			// Логика "после"
			c.Logger().Infof("%s %s — %v",
				c.Request().Method,
				c.Request().URL.Path,
				time.Since(start),
			)
			return err
		}
	}
}

Уровни регистрации

1. Глобальный middleware — e.Use()

e := echo.New()

// Применяется ко ВСЕМ маршрутам
e.Use(middleware.Logger())
e.Use(middleware.Recover())
e.Use(middleware.CORS())
e.Use(RequestTimer())

2. Middleware на группе маршрутов

// Только для /api/* маршрутов
api := e.Group("/api")
api.Use(middleware.KeyAuth(func(key string, c echo.Context) (bool, error) {
	return key == os.Getenv("API_KEY"), nil
}))

api.GET("/users", listUsers)
api.POST("/users", createUser)

// Вложенная группа с дополнительным middleware
admin := api.Group("/admin")
admin.Use(requireAdminRole)
admin.DELETE("/users/:id", deleteUser)

3. Middleware на конкретном маршруте

// Middleware передаётся после хендлера как дополнительные аргументы
e.GET("/secret", secretHandler,
	middleware.BasicAuth(func(user, pass string, c echo.Context) (bool, error) {
		return user == "admin" && pass == "pass", nil
	}),
)

Встроенные middleware из echo/middleware

  • middleware.Logger() — структурированный лог запросов.
  • middleware.Recover() — перехват паник, возврат 500.
  • middleware.CORS() — заголовки CORS с конфигом middleware.CORSConfig.
  • middleware.JWT(secret) — проверка Bearer-токена, claims в c.Get("user").
  • middleware.RateLimiter() — ограничение RPS через in-memory store.
  • middleware.Gzip() — сжатие ответов.
  • middleware.RequestID() — генерация X-Request-ID.
  • middleware.BodyLimit("2M") — ограничение размера тела.

Middleware с конфигурацией

e.Use(middleware.CORSWithConfig(middleware.CORSConfig{
	AllowOrigins: []string{"https://talento.work", "https://app.talento.work"},
	AllowMethods: []string{http.MethodGet, http.MethodPost, http.MethodPut, http.MethodDelete},
	AllowHeaders: []string{echo.HeaderContentType, echo.HeaderAuthorization},
	AllowCredentials: true,
}))

Передача данных между middleware и хендлером

// Middleware записывает данные
func SetUserID() echo.MiddlewareFunc {
	return func(next echo.HandlerFunc) echo.HandlerFunc {
		return func(c echo.Context) error {
			c.Set("userID", "123") // ключ-значение в контексте
			return next(c)
		}
	}
}

// Хендлер читает данные
func handler(c echo.Context) error {
	userID := c.Get("userID").(string)
	return c.JSON(http.StatusOK, map[string]string{"user": userID})
}

Подводные камни

  • Порядок регистрации = порядок выполнения: первый e.Use() — самый внешний. Logger должен идти до Recover, чтобы логировать даже паникующие запросы.
  • Middleware на группе не наследуется: middleware добавленный к e.Group("/api") не действует на маршруты, зарегистрированные прямо на e.
  • Middleware до регистрации маршрутов: e.Use() должен вызываться до e.GET/POST — иначе существующие маршруты не увидят middleware в некоторых сценариях.
  • c.Set() не потокобезопасен: запись и чтение из горутин без синхронизации вызывает гонку данных.
  • Middleware пропускает ошибку: если middleware не вызывает next(c), хендлер не выполняется — легко случайно заблокировать все запросы.
  • RateLimiter in-memory: встроенный RateLimiter не работает в multi-instance деплое — нужен Redis-бэкенд или внешний rate limiter.
  • CORS и Preflight: CORSWithConfig должен быть зарегистрирован до аутентификационного middleware, иначе OPTIONS-запросы будут отклоняться до проверки CORS-заголовков.
  • Паника в middleware: если Recover не первый в цепочке, паника в предшествующем middleware не будет перехвачена.

Common mistakes

  • Давать ответ про регистрация middleware в Echo только на уровне определения, не показывая поведение в реальном приложении.
  • Игнорировать границы ответственности вокруг темы «регистрация middleware в Echo»: кто отменяет работу, кто владеет ресурсом и где формируется ответ клиенту.
  • Не связывать регистрация middleware в Echo с observability, тестированием или безопасностью, когда это влияет на продакшен-поведение.

What the interviewer is testing

  • Точно объясняет, что именно делает регистрация middleware в Echo и где это используется в Go-коде.
  • Связывает регистрация middleware в Echo с корректным lifecycle запроса, отменой, конкурентностью или конфигурацией сервера там, где это уместно.
  • Не изобретает API и опирается на реальные контракты официальной документации.

Sources

Related topics