アプリケーションを作る際に、使うツールの仕組みが分かっていると自信が持てます。
Laravelも開発ツールの一つです。
Laravelの機能を理解することで、快適に開発できるようになります。
この記事では、Laravelのリクエストライフサイクルをについて説明しています。
Laravelの仕組みが分かることで、「なぜこうなるのか分からない」ということが減ります。
そのことは、アプリケーション構築の自信につながります。
本記事の内容
- リクエストライフサイクルのスタート
- HTTP/コンソール カーネル
- サービスプロバイダー
- ルーティング
- リクエストライフサイクルのまとめ
それでは、上記に沿って解説していきます。
リクエストライフサイクルのスタート
Laravelアプリケーションへの全てのリクエストの入り口は、public/index.phpファイルです。
すべてのリクエストは、Webサーバー(Apache / Nginx)の設定によってこのファイルに向けられます。
index.phpファイルには多くのコードは含まれていません。
主にフレームワークの他の部分を読み込む起点となっています。
index.phpはまず、Composerで生成されたオートローダーを読み込みます。
次に、bootstrap/app.phpからLaravelアプリケーションのインスタンスを取得します。
Laravelが真っ先にすることは、アプリケーション/サービスコンテナーのインスタンスを作成することです。
HTTP/コンソール カーネル
Laravelアプリケーションでは、入ってくるリクエストがHTTPカーネルまたはコンソールカーネルに送られます。
これは、リクエストの種類に依存します。
これら2つのカーネルが、すべてのリクエストが通過する中心地点となっています。
ここではまず、app/Http/Kernel.phpにあるHTTPカーネルに焦点を当てます。
HTTPカーネルは、Illuminate\Foundation\Http\Kernelクラスを拡張しています。
これには、リクエストが実行される前に起動するブートストラッパーの配列が定義されています。
ブートストラッパーに設定するのは、以下のような初期設定のことです。
- エラー処理の設定
- ログの設定
- アプリケーションの実行環境の検出
HTTPカーネルはまた、HTTPミドルウェアのリストも定義しています。
すべてのリクエストは、アプリケーションによって処理される前にHTTPミドルウェアを通過する必要があります。
HTTPミドルウェアは、ブートストラッパーの処理が完了した後に実行されます。
そのHTTPミドルウェアには、以下のような処理が含まれます。
- セッションの管理
- メンテナンスモードの確認
- CSRFトークンの検証
HTTPカーネルのhandleメソッドのシグネチャは非常にシンプルです。
Requestを受け取りResponseを返します。
カーネルがアプリケーション全体を表す大きなブラックボックスであると考えてください。
HTTPリクエストを入力してHTTPレスポンスを出力します。
サービスプロバイダー
カーネルのブートストラップアクションの中で最も重要なものの1つが、
アプリケーションのサービスプロバイダーを読み込むことです。
サービスプロバイダーは、Laravelの様々なコンポーネントの起動を担当します。
- データベース
- キュー
- バリデーション
- ルーティング
アプリケーションのすべてのサービスプロバイダーは、config/app.phpにproviders 配列で設定されます。
'providers' => ServiceProvider::defaultProviders()->merge([ /* * Package Service Providers... */ /* * Application Service Providers... */ App\Providers\AppServiceProvider::class, App\Providers\AuthServiceProvider::class, // App\Providers\BroadcastServiceProvider::class, App\Providers\EventServiceProvider::class, App\Providers\RouteServiceProvider::class, ])->toArray(),
Laravelはこのリストを通してサービスプロバイダーを初期化し、registerメソッド、そしてbootメソッドを呼び出します。
サービスプロバイダーはLaravelの主要な機能を起動・設定するため、ブートストラッププロセスで非常に重要です。
ルーティング
ルーティングでは、アプリケーションのApp\Providers\RouteServiceProviderが重要な役割を果たします。
このサービスプロバイダーは、アプリケーションのroutesディレクトリ内に含まれるルートファイルをロードします。
アプリケーションのブートストラップが完了したら、サービスプロバイダーが登録されます。
その状態において、リクエストはルーターに渡さることになります。
その結果、適切なルートやコントローラーにディスパッチされます。
また、ルーターは同時にルート固有のミドルウェアも実行します。
ミドルウェアは、HTTPリクエストをフィルタリングまたは検査するための便利なメカニズムを提供します。
例えば、Laravelにはユーザーの認証を確認するミドルウェア(Authenticate)が含まれています。
上記のファイルは、Laravel 10におけるデフォルトのミドルウェアとなります。
一部のミドルウェアは、HTTPカーネルの$middlewareプロパティで定義されています。
protected $middleware = [ // \App\Http\Middleware\TrustHosts::class, \App\Http\Middleware\TrustProxies::class, \Illuminate\Http\Middleware\HandleCors::class, \App\Http\Middleware\PreventRequestsDuringMaintenance::class, \Illuminate\Foundation\Http\Middleware\ValidatePostSize::class, \App\Http\Middleware\TrimStrings::class, \Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class, ];
$middlewareに設定したミドルウェアは、アプリケーション内のすべてのルートに割り当てられることになります。
先ほどのAuthenticateは設定されていませんね。
通常、ユーザー認証はログイン後のアプリケーションにおいて機能させます。
ユーザーが認証されていない場合、ミドルウェアはユーザーをログイン画面にリダイレクトします。
しかし、ユーザーが認証されている場合、ミドルウェアはリクエストをアプリケーションの奥へと進めます。
Authenticateのようなミドルウェアは、無条件でアプリケーション全体($middleware)に適用しません。
特定のルートやルートグループで明示的に使用されることになるでしょう。
リクエストライフサイクルのまとめ
ルートやコントローラーのメソッドがレスポンスを返すと、そのレスポンスはルートのミドルウェアを通じて外側に戻されます。
これにより、アプリケーションは発信レスポンスを変更または検査する機会が得られます。
つまり、各ページ(ルートやコントローラー)で以下のようなことを行う必要がないのです。
- セキュリティ関連の変更: クロスサイトリクエストフォージェリ(CSRF)トークンの確認、セキュリティヘッダーの追加。
- データの整形: レスポンスの内容をJSONやHTMLなど特定のフォーマットに整形。
- 認証と認可: ユーザーの認証状態を確認し、権限がない場合はアクセスを制限。
- パフォーマンス関連の最適化: レスポンスキャッシング、圧縮。
- エラーハンドリング: エラーレスポンスのカスタマイズ。
このような共通的な処理は、ミドルウェアで実行することになります。
そして、ミドルウェアを経由したレスポンスはHTTPカーネルに戻ってきます。
HTTPカーネルは、index.phpのことだと捉えてOK。
最終的には、sendメソッドによりレスポンスコンテンツをユーザーのウェブブラウザに送信します。
$response = $kernel->handle( $request = Request::capture() )->send();
確かに、index.phpには上記のようにコーディングされています。
以上により、Laravelリクエストライフサイクルが完了します。