Архитектурная концепция Laravel: Жизненный цикл запроса
Введение
При использовании любого инструмента в реальном мире
вы чувствуете себя увереннее, если понимаете, как этот инструмент работает. Разработка приложения ничем не отличается. Когда вы понимаете, как работают ваши инструменты разработки, вы чувствуете себя более комфортно и уверенно, используя их.
Цель этого документа — дать обзор того, как работает фреймворк Laravel. Лучше познакомившись с общей структурой, всё кажется менее волшебным
, и вы будете более уверенно создавать свои приложения. Если вы не понимаете сразу все термины, не отчаивайтесь! Просто попытайтесь получить общее представление о том что происходит, и ваши знания будут расти по мере изучения других разделов документации.
Обзор жизненного цикла
Первые шаги
Точкой входа всех запросов приложения Laravel является файл public/index.php
. Все запросы направляются в этот файл конфигурацией вашего веб-сервера (Apache/Nginx). Файл index.php
не содержит много кода. Скорее, это отправная точка для загрузки остальной части фреймворка.
Файл index.php
загружает сгенерированное Composer определение автозагрузчика, а затем извлекает экземпляр приложения Laravel из bootstrap/app.php
. Первое действие, предпринимаемое самим Laravel, — создание экземпляра приложения/сервис контейнера.
Узнать больше о Сервис Контейнер можно в статье Laravel: Сервис Контейнер — что нужно знать новичкам.
Ядра HTTP/Консоли
Затем входящий запрос отправляется либо в ядро HTTP
, либо в ядро Console
, в зависимости от типа запроса, поступившего в приложение. Эти два ядра служат центральной локацией, через которую проходят все запросы. А пока давайте просто сосредоточимся на ядре HTTP
, которое находится в app/Http/Kernel.php
Ядро HTTP
расширяет класс Illuminate\Foundation\Http\Kernel
, определяющий массив bootstrappers
— загрузчиков, которые будут выполняться перед выполнением запроса. Эти загрузчики настраивают обработку ошибок, настраивают логи, определяют среду/окружение приложения и выполняют другие задачи, которые необходимо выполнить до фактической обработки запроса. Обычно эти классы обрабатывают внутреннюю конфигурацию Laravel, о которой вам не нужно беспокоиться.
Ядро HTTP
также определяет список HTTP middleware, через которые должны пройти все запросы, прежде чем они будут переданы приложению. Эти middleware обрабатывают чтение и запись HTTP сессии, определяют, находится ли приложение в режиме обслуживания, проверят CSRF токены и многое другое. Мы поговорим об этом подробнее в ближайшее время.
Что такое CSRF и зачем нужны CSRF токены вы можете узнать в статьях CSRF: Подделка межсайтовых запросов и CSRF: Как предотвратить уязвимость
Сигнатура метода дескриптора ядра HTTP
довольно проста: он получает Request
и возвращает Response
. Думайте о ядре как о большом чёрном ящике, представляющем всё ваше Laravel приложение. Отправьте ему HTTP-запросы, и он вернёт HTTP-ответы.
Сервис Провайдеры
Одним из наиболее важных действий по начальной загрузке ядра является загрузка сервис провайдеров — поставщиков услуг вашего приложения. Сервис провайдеры несут ответственность за начальную загрузку различных компонентов фреймворка, таких, как базы данных, очередь, компоненты валидации и маршрутизации. Все сервис провайдеры приложения настраиваются в массиве providers
конфигурационного файла config/app.php
.
Laravel будет перебирать этот список провайдеров и создавать экземпляры каждого из них. После создания экземпляров провайдеров будет вызываться метод register
всех провайдеров. Затем, как только все провайдеры будут зарегистрированы, для каждого провайдера будет вызван метод boot
. Это сделано для того, чтобы сервис провайдеры могли зависеть от того, что каждая привязка контейнера будет зарегистрирована и доступна к моменту вызова метода boot
.
По сути, каждая основная функция, предлагаемая Laravel, загружается и настраивается сервис провайдером. Поскольку они загружают и настраивают так много функций, предлагаемых фреймворком, сервис провайдеры являются важным аспектом всего процесса начальной загрузки Laravel.
Маршрутизация
Одним из наиболее важных сервис провайдеров в вашем Laravel приложении является App\Providers\RouteServiceProvider
. Этот сервис провайдер загружает файлы маршрутов, содержащиеся в каталоге routes
вашего приложения. Вперёд, откройте код RouteServiceProvide
и посмотрите как он работает!
/app/Providers/RouteServiceProvider.php:
<?php
namespace App\Providers;
use Illuminate\Cache\RateLimiting\Limit;
use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\RateLimiter;
use Illuminate\Support\Facades\Route;
class RouteServiceProvider extends ServiceProvider
{
/**
* The path to the "home" route for your application.
*
* Typically, users are redirected here after authentication.
*
* @var string
*/
public const HOME = '/home';
/**
* Define your route model bindings, pattern filters, and other route configuration.
*/
public function boot(): void
{
$this->configureRateLimiting();
$this->routes(function () {
Route::middleware('api')
->prefix('api')
->group(base_path('routes/api.php'));
Route::middleware('web')
->group(base_path('routes/web.php'));
});
}
/**
* Configure the rate limiters for the application.
*/
protected function configureRateLimiting(): void
{
RateLimiter::for('api', function (Request $request) {
return Limit::perMinute(60)->by($request->user()?->id ?: $request->ip());
});
}
}
После загрузки приложения и регистрации всех сервис провайдеров Request
будет передан для обработки маршрутизатору. Маршрутизатор отправит запрос в маршрут или контроллер, а также запустит указанное middleware для данного маршрута.
Middleware предоставляет удобный механизм фильтрации и проверки HTTP-запросов, поступающих в ваше Laravel приложение. Например, Laravel включает middleware, проверяющее, аутентифицирован ли пользователь вашего приложения. Если пользователь не аутентифицирован, middleware перенаправит пользователя на страницу входа в приложение. Однако если пользователь аутентифицирован, middleware позволит запросу дальше обрабатываться в приложении. Некоторое middleware назначается всем маршрутам приложения, например, определённым в свойстве $middleware
вашего HTTP ядра, а некоторые назначаются только определённым маршрутам или группам маршрутов. Узнать больше о middleware вы можете из полной документации по middleware](https://laravel.com/docs/10.x/middleware).
Если запрос проходит через всё middleware соответствующего маршрута, будет выполнен метод маршрута или контроллера, а ответ, возвращённый методом маршрута или контроллера, будет отправлен обратно через цепочку middleware.
Завершение
Как только метод маршрута или контроллера вернёт ответ. Ответ будет отправлен обратно через middleware, давая приложению возможность изменить или проверить исходящий ответ.
Наконец, когда ответ возвращается через middleware, метод handle
ядра HTTP возвращает объект ответа, а файл index.php
вызывает метод send
для возвращённого ответа. Метод sand
отправляет содержимое ответа в веб-браузер пользователя. Мы завершили наше путешествие по всему жизненному циклу запроса в Laravel!
Сосредоточьтесь на сервис провайдерах
Сервис провайдеры действительно являются ключом к начальной загрузке приложения Laravel. Экземпляр приложения создаётся, сервис провайдеры регистрируются, и запрос передаётся загруженному приложению. Это действительно так просто!
Чёткое понимание того, как приложение laravel создаётся и загружается через сервис провайдеров, очень ценно. Сервис провайдеры вашего приложения по умолчанию хранятся в каталоге app/Providers
.
app/Providers/AppServiceProvider.php:
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*/
public function register(): void
{
//
}
/**
* Bootstrap any application services.
*/
public function boot(): void
{
//
}
}
По умолчанию AppServiceProvider
практически пуст. Этот провайдер — отличное место для добавления собственных загрузочных и сервисных привязок вашего приложения. Для большинства приложений вы можете создать несколько сервис провайдеров, каждый из которых будет выполнять более точную загрузку определённых сервисов/служб, используемых вашим приложением.