Кастомні 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 варіюється залежно від складності. Точну вартість розраховуємо індивідуально після аналізу вашого проекту.
Покрокове налаштування 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 тижні підтримки.







