Разработка кастомных middleware Strapi

Наша компания занимается разработкой, поддержкой и обслуживанием сайтов любой сложности. От простых одностраничных сайтов до масштабных кластерных систем построенных на микро сервисах. Опыт разработчиков подтвержден сертификатами от вендоров.

Разработка и обслуживание любых видов сайтов:

Информационные сайты или веб-приложения
Сайты визитки, landing page, корпоративные сайты, онлайн каталоги, квиз, промо-сайты, блоги, новостные ресурсы, информационные порталы, форумы, агрегаторы
Сайты или веб-приложения электронной коммерции
Интернет-магазины, B2B-порталы, маркетплейсы, онлайн-обменники, кэшбэк-сайты, биржи, дропшиппинг-платформы, парсеры товаров
Веб-приложения для управления бизнес-процессами
CRM-системы, ERP-системы, корпоративные порталы, системы управления производством, парсеры информации
Сайты или веб-приложения электронных услуг
Доски объявлений, онлайн-школы, онлайн-кинотеатры, конструкторы сайтов, порталы предоставления электронных услуг, видеохостинги, тематические порталы

Это лишь некоторые из технических типов сайтов, с которыми мы работаем, и каждый из них может иметь свои специфические особенности и функциональность, а также быть адаптированным под конкретные потребности и цели клиента

Предлагаемые услуги
Показано 1 из 1 услугВсе 2065 услуг
Разработка кастомных middleware Strapi
Средняя
~2-3 рабочих дня
Часто задаваемые вопросы

Наши компетенции:

Этапы разработки

Последние работы

  • image_website-b2b-advance_0.png
    Разработка сайта компании B2B ADVANCE
    1262
  • image_web-applications_feedme_466_0.webp
    Разработка веб-приложения для компании FEEDME
    1171
  • image_websites_belfingroup_462_0.webp
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    874
  • image_ecommerce_furnoro_435_0.webp
    Разработка интернет магазина для компании FURNORO
    1094
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    831
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Разработка веб-сайта для компании ФИКСПЕР
    851

Кастомные middleware в Strapi

Middleware в Strapi — функции, выполняемые до или после обработки запроса контроллером. Работают как Express/Koa middleware. Применяются глобально (ко всем маршрутам) или к конкретным маршрутам.

Типы middleware

Strapi различает:

  • Global middleware — применяется ко всем запросам, регистрируется в config/middlewares.js
  • Route middleware — применяется к конкретным маршрутам, регистрируется в конфигурации маршрута

Global middleware — логирование

// 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 — подключить глобально
module.exports = [
  'strapi::logger',
  'strapi::errors',
  'strapi::security',
  'strapi::cors',
  'global::request-logger',   // кастомный middleware
  'strapi::query',
  'strapi::body',
  'strapi::session',
  'strapi::favicon',
  'strapi::public',
]

Global middleware — Rate Limiting

// 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
{
  name: 'global::rate-limit',
  config: { maxRequests: 100, windowMs: 60000 }
}

Route 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()
  }
}
// src/api/premium-content/routes/premium-content.ts
export default {
  routes: [
    {
      method: 'GET',
      path: '/premium-content',
      handler: 'premium-content.find',
      config: {
        middlewares: ['api::premium-content.check-subscription'],
      },
    },
  ],
}

Middleware для трансформации ответа

// src/middlewares/add-computed-fields.ts
export default () => {
  return async (ctx: any, next: any) => {
    await next()

    // Добавить поля к ответу API после обработки
    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)
      }
    }
  }
}

Middleware для мультиязычных URL

// 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) => {
    // Если в заголовке Accept-Language есть локаль, добавить в query
    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, логирование, трансформация ответа) — 1–2 дня.