FiberMiddleCoding
Как реализовать rate limiting в Fiber?
Подключите github.com/gofiber/fiber/v2/middleware/limiter с limiter.New(limiter.Config{Max: N, Expiration: time.Minute}). Для распределённого окружения используйте Storage с Redis-бэкендом вместо памяти по умолчанию.
Rate limiting в Fiber
Fiber включает middleware github.com/gofiber/fiber/v2/middleware/limiter, реализующий алгоритм фиксированного окна (fixed window). Для sliding window и более тонкой настройки подключается Redis-хранилище.
Базовый пример (in-memory)
package main
import (
"time"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v2/middleware/limiter"
)
func main() {
app := fiber.New()
app.Use(limiter.New(limiter.Config{
Max: 100, // максимум запросов
Expiration: 1 * time.Minute, // за это окно
KeyGenerator: func(c *fiber.Ctx) string {
return c.IP() // ключ = IP клиента
},
LimitReached: func(c *fiber.Ctx) error {
return c.Status(fiber.StatusTooManyRequests).JSON(fiber.Map{
"error": "rate limit exceeded, try again later",
})
},
}))
app.Get("/", func(c *fiber.Ctx) error {
return c.SendString("OK")
})
app.Listen(":3000")
}
Распределённое хранилище (Redis)
In-memory хранилище не шарится между несколькими экземплярами приложения. Для горизонтального масштабирования подключите Redis через github.com/gofiber/storage/redis/v3:
import (
"github.com/gofiber/fiber/v2/middleware/limiter"
"github.com/gofiber/storage/redis/v3"
)
store := redis.New(redis.Config{
Host: "localhost",
Port: 6379,
Password: "",
Database: 0,
})
app.Use(limiter.New(limiter.Config{
Max: 200,
Expiration: 1 * time.Minute,
Storage: store,
}))
Разные лимиты для разных маршрутов
strictLimit := limiter.New(limiter.Config{
Max: 5,
Expiration: 15 * time.Minute,
})
looseLimit := limiter.New(limiter.Config{
Max: 1000,
Expiration: 1 * time.Minute,
})
// Строгий лимит только на /auth/login
app.Post("/auth/login", strictLimit, loginHandler)
// Мягкий лимит на все /api маршруты
app.Use("/api", looseLimit)
Ключ лимита по пользователю (после аутентификации)
app.Use("/api", jwtMiddleware, limiter.New(limiter.Config{
Max: 500,
Expiration: 1 * time.Minute,
KeyGenerator: func(c *fiber.Ctx) string {
// Берём user_id из JWT-claims, записанных jwtMiddleware
token := c.Locals("user").(*jwt.Token)
claims := token.Claims.(jwt.MapClaims)
if uid, ok := claims["user_id"]; ok {
return fmt.Sprintf("user:%v", uid)
}
return c.IP()
},
}))
Заголовки ответа
Middleware автоматически добавляет заголовки:
X-RateLimit-Limit— максимально допустимое количество запросов.X-RateLimit-Remaining— оставшееся количество запросов в текущем окне.X-RateLimit-Reset— Unix timestamp сброса счётчика.
Чтобы отключить эти заголовки, установите SkipFailedRequests: true или переопределите обработчик.
Подводные камни
- In-memory не работает горизонтально — при нескольких репликах каждый инстанс хранит свой счётчик; без Redis лимит де-факто умножается на количество экземпляров.
- IP-спуфинг через X-Forwarded-For —
c.IP()за прокси вернёт адрес прокси; используйтеapp := fiber.New(fiber.Config{TrustedProxies: []string{"10.0.0.0/8"}})иc.IP()правильно вернёт реальный IP только если прокси доверенный. - Алгоритм фиксированного окна — в конце одного окна и начале следующего пользователь может отправить
2 * Maxзапросов за короткий промежуток; для строгого ограничения используйте sliding window через кастомный Storage. - Порядок middleware — rate limiter должен стоять после CORS (иначе preflight заблокируется), но перед тяжёлой бизнес-логикой.
- Redis недоступен — при сбое Redis-хранилища middleware паникует или пропускает все запросы в зависимости от реализации; добавьте проверку соединения при старте.
- SkipSuccessfulRequests / SkipFailedRequests — легко перепутать:
SkipSuccessfulRequests: trueсчитает только ошибки (полезно против brute-force),SkipFailedRequests: trueсчитает только успешные запросы. - Отсутствие Retry-After — стандарт HTTP 429 предполагает заголовок
Retry-After; встроенный middleware его не выставляет — добавьте вручную вLimitReached.
Common mistakes
- Давать ответ про rate limiting в Fiber только на уровне определения, не показывая поведение в реальном приложении.
- Игнорировать границы ответственности вокруг темы «rate limiting в Fiber»: кто отменяет работу, кто владеет ресурсом и где формируется ответ клиенту.
- Не связывать rate limiting в Fiber с observability, тестированием или безопасностью, когда это влияет на продакшен-поведение.
What the interviewer is testing
- Точно объясняет, что именно делает rate limiting в Fiber и где это используется в Go-коде.
- Связывает rate limiting в Fiber с корректным lifecycle запроса, отменой, конкурентностью или конфигурацией сервера там, где это уместно.
- Не изобретает API и опирается на реальные контракты официальной документации.