最近、プロジェクト開発のニーズにより、モバイル クライアントと Web クライアントは、さまざまな状況下でセッションが正常で互換性があることを保証するために、統一されたインターフェイスのセットを使用するようになり、SessionID の取得方法を変更したいと考えています。デフォルトでは、すべての Web サイトは HTTP リクエストのヘッダー ヘッダーの Cookie を介して実装され、Cookie で指定された SessionID がサーバー側の対応するデータに関連付けられ、セッション機能が実装されます。
ただし、モバイル クライアントの場合、元の Cookie がサポートされないか、プラットフォームのニーズに応じてブロックされる可能性があるため、開発では SessionID を識別するためにリクエスト ヘッダー X-Session-Token を追加する必要があります。 Laravel フレームワークでは、セッションの初期化、読み取り、開始はすべて IlluminateSessionMiddlewareStartSession ミドルウェアによって実装されます。このミドルウェアには、SessionId を取得し、セッション データを復元するために使用する資格情報をセッション コンポーネントに伝えるための重要なメソッドがあります。
このミドルウェアは app/Http/Kernel.php ファイルの下に登録されます。
ミドルウェアを継承する新しいクラスを作成し、同時にapp/Http/Kernel.php以下の登録場所を置き換えました。元のgetSessionメソッドのソースコードは以下の通りです。
public function getSession(Request $request) { $session = $this->manager->driver(); $session->setId($request->cookies->get($session->getName())); return $session; }
新しいミドルウェアでは、変更しました。それは次のとおりです:
public function getSession(Request $request) { $session = $this->manager->driver(); // 判断是否是接口访问并根据实际情况选择 SessionID 的获取方式 if ($request->headers->has('x-session-token')) { $sessionId = $request->headers->has('x-session-token'); } else { $sessionId = $request->cookies->get($session->getName()); } $session->setId($sessionId); return $session; }
しかし、問題も起こります。 。 。
変更後、メインの開発ブランチにマージする前に、単体テストを実行する必要があることがよくあります。残念ながら、今回は CSRF コンポーネントがエラーを報告したことが問題です。トークン エラーが発生し、ここにいます。 1 か所で提供されたトークンは通常と変わりません。問題はセッションにあるはずです。
ミドルウェア コードを変更する場合、フレームワークにはまったく影響を与えないと言えることに注意してください。実際には、作成したミドルウェア コードを変更しても役に立たないためです。しかし、奇妙なことに、ミドルウェアを元のミドルウェアに戻した後は、この問題は発生しません。
そこで、通常の状態と異常な状態でコードを実行し、重要なポイントにブレークポイントを使用してデバッグしたところ、問題はミドルウェアの重要な属性である $sessionHandled にあることがわかりました。この値が false の場合、問題が発生します。私たちは以前にステータスを持っていました。重要なのは、ミドルウェアの起動時にハンドル メソッドが使用されるということです。セッション ミドルウェアの場合、ハンドル メソッドのコードの最初の行は、
$this->sessionHandled = true;
です。 。 。
私たちは知っています。 Laravel フレームワークの特徴は IoC コンテナです。IoC コンテナは、フレームワーク内のさまざまなクラスを初期化してさまざまな依存関係の注入を実装し、コンポーネント間の疎結合を確保します。ミドルウェアも例外ではありません。シングルトンと通常のインスタンスの最大の違いは、シングルトンは何度作成しても常に同じであり、インスタンス内のプロパティは初期化されないため、問題がないことを知っておく必要があります。ミドルウェアはシングルトンである必要があり、私が自分で作成したミドルウェアは通常のクラスのインスタンスにすぎません。しかし、何が起こっているのか、そしてその理由を知るためには、自分のアイデアを確認する必要があります (実際、解決策はすでに考えられています。これについては後で説明します)。
それでは、問題はおおよそミドルウェアの初期化なので、気を取り直してLaravelのスタートアップコードを詳しく見てみる必要があります。ここでの重要なポイントは、IlluminatePipelinePipeline というクラスにあります。
このクラスには、send、through、then という 3 つの重要なメソッドがあります。それでは、すべてを開始する鍵はどこにあるのでしょうか。このクラスは主にフレームワークの複数の起動ステップを連続的に実行するもので、1つ目は処理プロセスに必要なコンポーネント(リクエストとミドルウェア)を初期化し、2つ目はこれらの処理コンポーネント(集合体)で構成されるスタックにリクエストを渡すことです。ミドルウェアやルーティングディスパッチコンポーネントなど)を実行し、最後に処理結果(Response)を返します。
これは、Laravel Http 部分 (まあ、本来は Kernel です) の中核であると言えます。次に、前述の問題は Pipeline の then メソッドとそれが呼び出す getSlice メソッドにあります。 getSlice メソッドを直接観察すると、このメソッドが処理スタックの生成と Middleware クラスのインスタンス化を担当していることがわかります。メソッド コード全体は次のとおりです。
$this->container->make($name) は、ミドルウェア クラスを初期化することを意味し、単に make であることがわかります。これがシングルトンでない場合、 new が繰り返され、前の属性が無効になります。初期化される。