Увійти Реєстрація
Блог Серії
Кар'єра
Вакансії Компанії
Навчання
Документація Співбесіди Тестування Відео
Екосистема
Пакети Ресурси Проєкти Інструменти Події
Інше
Про нас Реклама

Питання на співбесіді: Middleware

Найпопулярніші питання з реальних Laravel/PHP співбесід для всіх рівнів

3 питання

Middleware - це шар фільтрації HTTP-запитів, що «обгортає» обробку: код може виконатися до того, як запит дійде до контролера, і/або після формування відповіді. Уявіть це як серію «застав», крізь які проходить кожен запит.

Створити middleware:

php artisan make:middleware EnsureUserIsActive

Логіка - у методі handle(); ключове - викликати $next($request), щоб передати запит далі конвеєром:

public function handle(Request $request, Closure $next): Response
{
    if (! $request->user()?->is_active) {
        return redirect('login'); // перервати конвеєр
    }

    return $next($request); // пропустити далі
}

Реєстрація та призначення (у Laravel 11+ - у bootstrap/app.php), застосування до маршрутів:

Route::get('/dashboard', ...)->middleware('auth');
Route::middleware(['auth', 'verified'])->group(fn () => ...);

Типові вбудовані middleware: auth (автентифікація), throttle (обмеження частоти), verified (підтверджений email), signed (підписані URL). Middleware - основа для авторизації, логування, CORS, локалізації.

Докладніше в документації: Middleware

Звичайне 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().

Докладніше в документації: Middleware

Middleware утворюють «цибулю» навколо обробки запиту: кожен бачить запит на вході й відповідь на виході у зворотному порядку. Порядок вирішує, бо одні залежать від роботи інших.

Зазвичай він визначається місцем реєстрації: глобальні → групові → маршрутні. Але middleware, призначені маршруту, сортуються за списком пріоритетів, а не за тим, як їх перелічили в ->middleware([...]).

Чому це важливо. SubstituteBindings резолвить {post} у модель. Політика, що перевіряє власника поста, має спрацювати після цього - інакше отримає рядок замість моделі. Так само аутентифікація мусить йти раніше за авторизацію: перевіряти права нема в кого, поки користувач не визначений.

Задати свій порядок у bootstrap/app.php:

->withMiddleware(function (Middleware $middleware) {
    $middleware->priority([
        \Illuminate\Cookie\Middleware\EncryptCookies::class,
        \Illuminate\Session\Middleware\StartSession::class,
        \Illuminate\Auth\Middleware\Authenticate::class,
        \Illuminate\Routing\Middleware\SubstituteBindings::class,
        \App\Http\Middleware\EnsureSubscribed::class,
        \Illuminate\Auth\Middleware\Authorize::class,
    ]);
})

Ті, що є в списку, ідуть у вказаному порядку; решта - за порядком призначення.

Ознака, що ви натрапили саме на це: middleware працює на одному маршруті й «не бачить» даних на іншому, хоча код той самий. Зазвичай це означає, що щось потрібне ще не встигло відпрацювати.

Порада: не переставляйте наосліп. Спершу зʼясуйте, від чого залежить ваше middleware - від сесії, від резолвленої моделі, від автентифікованого користувача, - і поставте його після цього.

Докладніше в документації: Middleware