Посредники (Middleware)

Введение: Почему Middleware окружает столько мифов
Посредники (Middleware) — один из самых гибких механизмов Laravel, но именно вокруг него сломано больше всего копий. Разработчики часто путают middleware с контроллерами, боятся написать свою проверку авторизации или думают, что посредники сильно тормозят приложение. На самом деле middleware — это просто слой обработки HTTP-запроса до того, как он попадёт в контроллер. В этой статье мы разберём пять главных мифов, подкрепим каждый конкретными примерами кода и покажем, как на самом деле нужно работать с посредниками в 2026 году.
Миф 1: Middleware — это то же самое, что валидация в контроллере
Одна из самых частых ошибок — дублировать проверки в middleware и в контроллере. Многие думают, что если поставить фильтр в посреднике, то в контроллере можно ничего не проверять. Это неверно по двум причинам. Во-первых, middleware срабатывает до контроллера, но он не может отменить запрос после того, как контроллер начал работу. Во-вторых, задачи у них принципиально разные: middleware отвечает за «допуск» (авторизация, подпись, CORS), а контроллер — за бизнес-логику самой операции.
- Пример: проверка API-токена в middleware 'auth:api' не отменяет необходимости проверить права доступа к конкретной модели внутри контроллера.
- Практика: middleware проверяет кто делает запрос; контроллер проверяет что разрешено делать с конкретным ресурсом.
- Инструмент: используйте 'middleware → проверка идентичности', 'контроллер → проверка прав через Gate или Policy'.
Миф 2: Свой middleware писать сложно и долго
Начинающие часто боятся создавать собственные классы-посредники, думая, что это требует глубокого знания ядра Laravel. На деле для создания middleware нужно выполнить всего три действия: запустить artisan-команду php artisan make:middleware CheckAge, написать логику в методе handle() и зарегистрировать класс в app/Http/Kernel.php. Весь процесс занимает меньше 5 минут. Единственный нюанс — не забыть вернуть $next($request) в конце метода, иначе запрос «зависнет».
- Команда:
php artisan make:middleware LogRequests— создаёт заготовку за секунду. - Типичная ошибка: отсутствие вызова
$next($request)— запрос не дойдёт до контроллера. - Регистрация: добавьте класс в массив
$routeMiddlewareв Kernel.php, чтобы использовать через ключ 'log.requests'в маршруте.
Миф 3: Middleware сильно замедляет приложение
Многие считают, что каждый добавленный посредник добавляет ощутимую задержку. На практике один middleware в среднем потребляет 0.02–0.05 мс процессорного времени (данные профилировщика Laravel Debugbar при тестах на Laravel 11 в 2026 году). Даже 10–15 посредников в цепочке дают суммарную задержку менее 1 мс. Проблемы производительности возникают только когда в middleware выполняются тяжёлые операции (запросы к БД, HTTP-вызовы внешних API) без кэширования. Профилируйте код и переносите тяжёлую работу в отложенные задачи или кэш.
- Факт: стандартный middleware 'throttle' добавляет меньше 0.1 мс к времени ответа.
- Что реально тормозит: запрос к БД внутри middleware, который не использует кэш Redis или Memcached.
- Решение: кэшируйте результаты проверок (например, роль пользователя) на время запроса или используйте
Cache::remember().
Миф 4: Middleware не может взаимодействовать с сессией или кэшем
Существует мнение, что middleware работает «ниже» сессии, поэтому читать данные из неё нельзя. На деле middleware выполняется после того, как Laravel запустил сессионный драйвер (если он включён). В методе handle() вы имеете полный доступ к объекту запроса, который уже содержит информацию о сессии. Вы можете читать $request->session(), писать туда данные, а также использовать любой кэш-драйвер через фасад Cache. Единственное ограничение: если вы работаете с сессией в middleware, который выполняется до старта сессии (например, 'web' middleware в некоторых конфигурациях), нужно добавить middleware StartSession в ваш кастомный посредник.
- Доступ:
$request->session()->get('user_id')работает внутри middleware. - Кэш:
Cache::tags(['middleware'])->remember('key', 3600, function() { ... });— ускоряет проверки. - Важно: если middleware стоит до
StartSession, сессия не инициализирована — проверяйте порядок в Kernel.php.
Миф 5: После отказа от middleware всё равно придётся вернуться к контроллерам
Некоторые разработчики пытаются «упростить» архитектуру, убирая все middleware и перенося проверки в конструктор контроллера. Это приводит к тому, что одна и та же проверка дублируется в десятке контроллеров, код становится жёстким, а его тестирование — кошмаром. Middleware — единственный способ гарантировать, что проверка выполняется до любой бизнес-логики, для всех маршрутов, где она прописана. Если вы удалите middleware, вы потеряете возможность централизованно отключать проверки (например, при тестировании с подменой ролей).
- Альтернатива без middleware: написать трейт и подмешивать его в каждый контроллер — больше кода, выше шанс ошибки.
- Тестирование: middleware легко мокаются через
->withoutMiddleware()в тестах; контроллерные проверки не отключить разом. - Реальный пример: проверка 'verified' (подтверждение email) в middleware — вы не сможете её перенести в контроллер без нарушения DRY.
Пошаговая инструкция: Создаём и тестируем собственный Middleware за 7 шагов
- Создайте класс: выполните
php artisan make:middleware CheckSubscription. Получите файлapp/Http/Middleware/CheckSubscription.php. - Напишите логику: в методе
handle($request, Closure $next)добавьте проверкуif (!$request->user() || !$request->user()->subscribed()) { abort(403, 'Подписка неактивна'); }. Не забудьте вернутьreturn $next($request);. - Зарегистрируйте middleware: откройте
app/Http/Kernel.phpи добавьте в массив$routeMiddlewareстроку'subscribed' => \App\Http\Middleware\CheckSubscription::class. - Примените к маршруту: в файле маршрутов
routes/web.phpукажитеRoute::get('/premium', [PremiumController::class, 'index'])->middleware('subscribed');. - Протестируйте без middleware: в тесте PHPUnit добавьте
$response = $this->withoutMiddleware(CheckSubscription::class)->get('/premium');— проверьте, что доступ открывается. - Протестируйте с middleware:
$response = $this->actingAs(User::factory()->unsubscribed()->create())->get('/premium');— ожидайте статус 403. - Оцените производительность: подключите Laravel Debugbar, измерьте время выполнения middleware — оно не должно превышать 0.1 мс для простой проверки.
Практические советы для повседневной работы
- Группировка: используйте именованные группы middleware в Kernel.php (например, 'payment' => ['auth', 'subscribed']), чтобы не повторять длинные цепочки.
- Middleware с параметрами: передавайте параметры через двоеточие —
->middleware('role:admin,editor')— и принимайте их вhandle($request, Closure $next, ...$roles). - Терминальные middleware: реализуйте интерфейс
TerminableMiddleware, если нужно выполнить действие после отправки ответа (логирование, очистка). - Приоритет: в массиве
$middlewarePriorityзадайте порядок выполнения глобальных посредников — критично для корректной работы сессии и CSRF. - Избегайте тяжелых операций: не делайте запросы к внешним API внутри middleware без кэша — перенесите в событие или джобу.
- Документируйте назначение: комментарий PHPDoc над классом middleware с примерами маршрутов сэкономит часы отладки команде.
- Используйте artisan-команды:
php artisan route:middlewareпокажет список всех зарегистрированных посредников с их псевдонимами.
Заключение: Middleware — ваш лучший друг, если знать правду
Мы разобрали пять мифов, которые мешают разработчикам эффективно использовать middleware в Laravel. Запомните главное: посредники не дублируют контроллеры, не тормозят приложение (если не загружать их тяжёлыми запросами), легко создаются и тестируются. В 2026 году, когда производительность и безопасность стоят на первом месте, правильная организация middleware — это не роскошь, а необходимость. Начните с малого: создайте один кастомный middleware для проверки подписки или логирования, и вы увидите, как упростится архитектура всего проекта.
Добавлено: 23.04.2026
