Middle: питання на співбесіді з теми «Middleware»
Питання з реальних співбесід з відповідями: Laravel і PHP, бази даних, JavaScript і фронтенд, Git, Docker, API, безпека й архітектура. Тими самими темами, що й тести.
3 питання
Звичайне middleware працює навколо запиту: щось робить до $next($request), щось - після, але завжди до того, як відповідь піде користувачу.
Terminable middleware виконується після відправлення відповіді:
class LogRequestDuration
{
public function handle(Request $request, Closure $next): Response
{
return $next($request);
}
public function terminate(Request $request, Response $response): void
{
// Користувач уже отримав сторінку - це його не затримує.
RequestLog::create([
'path' => $request->path(),
'status' => $response->getStatusCode(),
'duration' => microtime(true) - LARAVEL_START,
]);
}
}
Метод terminate() викликається з $app->terminate() після send().
Важлива умова: це працює лише коли сервер уміє віддати відповідь і продовжити виконання - тобто на FastCGI з fastcgi_finish_request(). За іншої конфігурації користувач усе одно чекатиме.
Ще одна деталь: за замовчуванням у terminate() потрапляє новий екземпляр middleware. Якщо потрібен той самий - зареєструйте його синглтоном:
$this->app->singleton(LogRequestDuration::class);
Для чого доречно: запис аналітики, логування тривалості, дрібне прибирання - те, що не впливає на відповідь.
Для чого ні: будь-що довге. Воно все одно тримає PHP-воркер зайнятим, тож ця робота належить у чергу, а не в terminate().
Параметри пишуть після двокрапки, кілька - через кому. У handle() вони приходять після $next.
Route::put('/posts/{post}', [PostController::class, 'update'])
->middleware('role:editor,admin');
class EnsureUserHasRole
{
public function handle(Request $request, Closure $next, string ...$roles): Response
{
if (! $request->user()?->hasAnyRole($roles)) {
abort(403);
}
return $next($request);
}
}
Знайомі приклади з фреймворку:
throttle:60,1- 60 запитів на хвилину;can:update,post- перевірка політики з моделлю з параметра маршруту;auth:sanctum- гард для автентифікації;cache.headers:public;max_age=3600- параметри через крапку з комою.
Без рядків: вбудовані middleware мають статичні методи using(), що збирають цей рядок, - так IDE бачить посилання на клас:
->middleware(ThrottleRequests::using('uploads'))
->middleware(Authorize::using('update', 'post'))
Для власного middleware такий метод легко додати самому.
Якщо параметрів стає багато чи вони складні, це сигнал, що перевірку краще перенести в політику чи запит форми.
Групи підключаються автоматично: web - до routes/web.php, api - до routes/api.php.
Група web - усе для сторінок у браузері:
EncryptCookiesіAddQueuedCookiesToResponse- шифровані cookie;StartSession- сесія;ShareErrorsFromSession- змінна$errorsу шаблонах;PreventRequestForgery- захист від CSRF (у Laravel 13 спершу перевіряє заголовокSec-Fetch-Site, потім токен);SubstituteBindings- прив'язка моделей до параметрів маршруту.
Група api - лише SubstituteBindings. Немає сесії, cookie й CSRF: API зазвичай автентифікується токеном (auth:sanctum) і не тримає стану.
Наслідки, про які питають:
- маршрут з
routes/api.phpне бачить сесії йold(); - SPA на тому самому домені через Sanctum працює з cookie - для цього Sanctum додає потрібні middleware до
apiчерезstatefulApi(); routes/api.phpу свіжому Laravel 11+ немає - його створюєphp artisan install:api.
Додати своє в групу:
->withMiddleware(function (Middleware $middleware): void {
$middleware->web(append: [SetLocale::class]);
$middleware->api(prepend: [ForceJsonResponse::class]);
})