Laravelのデフォルトセッションミドルウェア拡張によるセッション書き込み失敗問題の分析

高洛峰
リリース: 2016-12-27 10:04:12
オリジナル
1072 人が閲覧しました

最近、プロジェクト開発のニーズにより、モバイル クライアントと 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 が繰り返され、前の属性が無効になります。初期化される。


その場合、解決策は明らかで、シングルトンにします。

app/Providers/AppServiceProvider.php の register メソッドに次のコード行を追加しました。これにより、以前の問題が解決されました。

$this->app->singleton(SessionStart::class);は私のミドルウェアクラス名です

上記は、Laravel のデフォルトのセッションミドルウェアの拡張によって引き起こされるセッション書き込み失敗の問題の分析をすべて紹介しました。気に入っていただければ幸いです。

Laravel のデフォルトのセッションミドルウェアの拡張によって引き起こされるセッション書き込みエラーの分析に関するその他の関連記事については、PHP 中国語 Web サイトに注目してください。

ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のおすすめ
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート