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

Senior: питання на співбесіді з теми «Middleware»

Питання з реальних співбесід з відповідями: Laravel і PHP, бази даних, JavaScript і фронтенд, Git, Docker, API, безпека й архітектура. Тими самими темами, що й тести.

2 питання

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

Код до $next($request) виконується до контролера, код після - коли відповідь уже готова.

public function handle(Request $request, Closure $next): Response
{
    $start = hrtime(true);

    $response = $next($request);

    $response->headers->set('Server-Timing', 'app;dur='.(hrtime(true) - $start) / 1e6);
    $response->headers->set('X-Frame-Options', 'SAMEORIGIN');

    return $response;
}

Типові задачі «після»: заголовки безпеки, Cache-Control, кореляційний ID запиту, вимірювання часу.

На що зважати:

  • Порядок. На вході middleware виконуються за списком, на виході - у зворотному порядку. Middleware, що ставить Cache-Control, має йти після того, що може його змінити. Laravel дозволяє задати пріоритет (priority() у bootstrap/app.php).
  • Потокові й файлові відповіді. StreamedResponse і BinaryFileResponse не мають готового тіла - не можна читати чи змінювати getContent(), лише заголовки.
  • Глобальний чи маршрутний. Глобальний middleware спрацьовує навіть для 404 і на запити до Livewire чи ресурсів, тож важка логіка там коштує на кожен запит.
  • Чужі middleware можуть перетерти заголовок. Наприклад, Livewire ставить no-store глобально, тож власний middleware, що робить сторінку кешованою, мусить бути в тому самому глобальному стеку й іти після нього.
  • Робота після відповіді - не тут, а в terminate() чи defer(): інакше користувач чекає.

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