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 - від сесії, від резолвленої моделі, від автентифікованого користувача, - і поставте його після цього.
Код до $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(): інакше користувач чекає.