Кастомные middleware Strapi
Ваш Strapi-проект тормозит при 1000 запросах в минуту? Логи разбросаны, а клиенты жалуются на 429 ошибки? Типовая ситуация: навигация начинает подтормаживать, а время ответа проседает до 800 мс. Чтобы это исправить, мы внедряем кастомные middleware — функции, перехватывающие запросы до и после обработки контроллером. Наш опыт: реализовали такие middleware для 50+ проектов — от интернет-магазинов до сложных CMS. Кастомные middleware Strapi позволяют гибко управлять запросами: ограничивать частоту, логировать, проверять подписки, трансформировать ответы.
Middleware (промежуточное ПО) — это концепция, знакомая разработчикам Express или Koa: они работают в цепочке, передавая управление через вызов await next(). Strapi поддерживает два типа: глобальные (применяются ко всем маршрутам) и маршрутные (только к определённым). Вот их сравнение:
| Тип | Область применения | Регистрация |
|---|---|---|
| Global | Все запросы | config/middlewares.js |
| Route | Конкретный маршрут | Конфигурация маршрута |
Как rate limiting влияет на производительность Strapi?
In-memory rate limiting — один из самых востребованных middleware. Он хранит временные метки запросов по IP в Map. Как только количество запросов за окно (например, 100 за 60 секунд) превышает лимит, возвращается 429. In-memory быстрее файлового в 10 раз — задержка минимальна. Для распределённых систем используем Redis; мы помогаем и с этим. Вот типовой код:
// src/middlewares/rate-limit.ts const requests = new Map<string, number[]>() export default (config: any) => { const { maxRequests = 100, windowMs = 60_000 } = config return async (ctx: any, next: any) => { const ip = ctx.request.ip const now = Date.now() const windowStart = now - windowMs const timestamps = (requests.get(ip) || []).filter(t => t > windowStart) if (timestamps.length >= maxRequests) { ctx.status = 429 ctx.body = { error: 'Too Many Requests' } ctx.set('Retry-After', String(Math.ceil(windowMs / 1000))) return } timestamps.push(now) requests.set(ip, timestamps) await next() } } Конфигурация в config/middlewares.js подключается как 'global::rate-limit' с параметрами maxRequests и windowMs.
In-memory rate limiting с Map даёт задержку менее 1 мс, Redis — 1-3 мс, но масштабируется горизонтально. Для проектов с нагрузкой до 1000 запросов/сек достаточно in-memory, от 1000 до 5000 — используем Redis. На одном проекте (интернет-магазин) после внедрения rate limiting и кеширующего middleware TTFB упал с 800 мс до 200 мс, а 429 ошибки исчезли полностью. Это позволило сэкономить около $500 в месяц на серверных ресурсах (расчёт экономии по проекту).
Зачем логировать запросы через middleware?
Стандартный логгер Strapi не умеет отслеживать медленные запросы. Кастомный middleware с таймингом решает это: логирует все запросы и помечает медленные (более 1 секунды). Это помогает находить узкие места до того, как они станут критическими. Пример:
// src/middlewares/request-logger.ts export default (config: any, { strapi }: any) => { return async (ctx: any, next: any) => { const start = Date.now() await next() const duration = Date.now() - start const { method, url, status } = ctx if (duration > 1000) { strapi.log.warn(`Slow request: ${method} ${url} — ${duration}ms (${status})`) } strapi.log.debug(`${method} ${url} — ${duration}ms [${status}]`) } } Подключается глобально через config/middlewares.js. Гарантируем, что после настройки вы не пропустите ни одного проблемного запроса.
Как мы реализуем проверку подписки через middleware?
Для премиум-контента используем route middleware, проверяющий активную подписку у пользователя. Такой middleware применяется только к одному маршруту, не нагружая остальные:
// src/middlewares/check-subscription.ts export default (config: any, { strapi }: any) => { return async (ctx: any, next: any) => { const userId = ctx.state.user?.id if (!userId) { ctx.unauthorized('Authentication required') return } const user = await strapi.entityService.findOne( 'plugin::users-permissions.user', userId, { populate: ['subscription'] } ) if (!user?.subscription?.active) { ctx.forbidden('Active subscription required') return } await next() } } В конфигурации маршрута добавляется поле middlewares: ['api::check-subscription'].
Почему middleware важны для Core Web Vitals?
Каждый middleware может улучшить Core Web Vitals. Например, кеширующий middleware сокращает TTFB, а rate limiting предотвращает перегрузку сервера и падение INP. Если ваш API возвращает данные за 800 мс, это напрямую влияет на LCP. Middleware могут кешировать ответы или ограничивать частоту, снижая задержку.
Трансформация ответов и мультиязычность
Часто нужно добавить вычисляемое поле — например, размер скидки. Middleware перехватывает ответ и добавляет discountPercent. А для мультиязычных проектов — middleware, автоматически определяющий локаль из заголовка Accept-Language:
// src/middlewares/add-computed-fields.ts export default () => { return async (ctx: any, next: any) => { await next() if (ctx.url.startsWith('/api/products') && ctx.body?.data) { const transform = (item: any) => ({ ...item, attributes: { ...item.attributes, discountPercent: item.attributes.originalPrice ? Math.round((1 - item.attributes.price / item.attributes.originalPrice) * 100) : 0, }, }) if (Array.isArray(ctx.body.data)) { ctx.body.data = ctx.body.data.map(transform) } else { ctx.body.data = transform(ctx.body.data) } } } } // src/middlewares/locale-redirect.ts const localeMap: Record<string, string> = { 'ru-RU': 'ru', 'en-US': 'en', 'uk-UA': 'uk', } export default () => { return async (ctx: any, next: any) => { if (!ctx.query.locale) { const acceptLang = ctx.get('Accept-Language')?.split(',')[0] || 'ru' const locale = localeMap[acceptLang] || acceptLang.split('-')[0] || 'ru' ctx.query.locale = locale } await next() } } Какие middleware нужны для продакшена?
Обязательный набор включает rate limiting, логирование, аутентификацию/авторизацию и трансформацию ответов. Дополнительно можно добавить кеширование, редиректы, CORS. Мы помогаем подобрать оптимальный набор под вашу нагрузку. Стоимость разработки комплекта из 3-4 middleware варьируется от 10 000 до 50 000 руб. в зависимости от сложности. Точную стоимость рассчитываем индивидуально после анализа вашего проекта.
Пошаговая настройка rate limiting middleware
- Создайте файл
src/middlewares/rate-limit.tsс кодом из примера. - В
config/middlewares.jsдобавьте'global::rate-limit'в массивmiddlewares. - Настройте параметры
maxRequestsиwindowMsпод вашу нагрузку. - Протестируйте локально командой
npx strapi develop. - Для продакшена используйте Redis через внешнее хранилище.
Подробнее о конфигурации middleware читайте в официальной документации Strapi.
Процесс работы и что входит
Мы работаем так: анализируем требования → проектируем архитектуру middleware → пишем код с тестами → разворачиваем на staging → деплоим в продакшен. В результат входит:
- Исходный код middleware с комментариями
- Документация по установке и настройке
- Доступ к репозиторию (Git)
- Обучение вашей команды (1 час онлайн)
- Поддержка 2 недели после запуска
Сроки ориентировочно
Разработка набора из 3-4 middleware (rate limiting, логирование, проверка подписки, трансформация) занимает от 1 до 2 дней. Стоимость рассчитывается индивидуально.
Свяжитесь с нами для оценки вашего проекта — мы подберём оптимальный набор middleware под вашу нагрузку. Получите консультацию по кастомным middleware Strapi и закажите разработку под ключ с гарантией 2 недели поддержки.







