Laravelのデフォルトのセッションミドルウェアの拡張が原因でセッション書き込みエラーが発生する

WBOY
リリース: 2016-06-20 12:40:57
オリジナル
875 人が閲覧しました

最近、プロジェクト開発のニーズにより、モバイル クライアントと Web ページは、さまざまな状況下でセッションが正常で互換性があることを保証するために、統一されたインターフェイスを使用するようになりました。セッションIDの方法。デフォルトでは、すべての 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;}
ログイン後にコピー

In In新しいミドルウェアを

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 コンポーネントがトークン エラーを報告しました。ここで提供するトークンは通常のものと変わりません。問題はセッションにあるはずです。

ミドルウェア コードを変更しても、フレームワークにはまったく影響を与えないと言えることに注意してください。実際には、作成したミドルウェア コードを変更したためです。継承されたミドルウェア コードの一貫性も役に立ちませんが、不思議なことに、ミドルウェアを元のミドルウェアに戻した後は、この問題は発生しません。

そこで、通常の条件と異常な条件でコードを実行し、重要なポイントにブレークポイントを使用してデバッグしたところ、問題はミドルウェアの重要な属性である $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 が繰り返されます。 、その結果、以前のプロパティが初期化されます。

解決策は明らかで、シングルトンにします。
protected function getSlice(){    return function ($stack, $pipe) {        return function ($passable) use ($stack, $pipe) {            if ($pipe instanceof Closure) {                return call_user_func($pipe, $passable, $stack);            } else {                list($name, $parameters) = $this->parsePipeString($pipe);                return call_user_func_array([$this->container->make($name), $this->method],                                            array_merge([$passable, $stack], $parameters));            }        };    };}
ログイン後にコピー

次のコード行を app/Providers/AppServiceProvider.php の register メソッドに追加することで、前の問題を解決しました。

実際、それはとても簡単です。この記事はとても長いので、皆さんがもっと面白いことを学べることを願っています~~

$this->app->singleton(SessionStart::class); // SessionStart 是我那个中间件类名
ログイン後にコピー

ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート
私たちについて 免責事項 Sitemap
PHP中国語ウェブサイト:福祉オンライン PHP トレーニング,PHP 学習者の迅速な成長を支援します!