序文 HTTP はステートレスな通信プロトコルです。各リクエストは互いに独立しており、サーバーは以前のリクエストを識別できません。 Web アプリケーションの場合、そのアクティビティはすべて、ユーザーのログインなどの特定の状態に依存します。現時点では、HTTP を使用するには、ログイン要求後の後続の要求に対してログイン情報を提供できる必要があります。この記事は、最初に公開アカウント Dunwu Source Code で公開されました。 解決策は、サーバーからブラウザに返される Cookie を使用することです。ブラウザは Cookie データをキャッシュし、リクエストごとにサーバーに送信します。クッキーはリクエスト内でプレーンテキストで送信され、サイズは 4KB に制限されています。明らかに、すべての状態データをブラウザに保存するのは信頼性に欠けます。主流のアプローチは次のとおりです。
管理を容易にするために、サーバーはプロセス全体をセッションと呼び、それを Session クラスに抽象化します。このクラスは、ユーザーに関する情報やステータスを識別して保存するために使用されます。 1. セッション識別子を解決する Cookie は最も一般的に使用されるセッション トラッキング メカニズムです。Tomcat を含むすべてのサーブレット コンテナーがこれをサポートしています。Tomcat では、セッション ID を保存する Cookie の標準名は JSESSIONID です。 ブラウザが Cookie をサポートしていない場合は、次の方法で識別子を記録することもできます。
Tomcat は、URL 書き換えパスと Cookie から JSESSIONID を抽出する機能を実装します。ソース コードを分析する前に、まず、Cookie を設定するための応答と Cookie を含むリクエストのヘッダー フィールドの重要な情報を確認します。 // クッキーを設定 HTTP/1.1 200 OK サーバー: Apache-Coyote/1.1 Cookie の設定: JSESSIONID=56AE5B92C272EA4F5E0FBFEFE6936C91; パス=/examples 日付: 2019年5月12日(日)01:40:35 GMT // クッキーを送信 GET /examples/servlets/servlet/SessionExample HTTP/1.1 ホスト: localhost:8080 クッキー: JSESSIONID=56AE5B92C272EA4F5E0FBFEFE6936C91 1.1 URLからのパスの書き換え セッション ID パス パラメータを含む URL は次のとおりです。
簡単に言えば、一致するセミコロンと最後のスラッシュの間の JSESSIONID を見つけることです。これは確かにその通りですが、Tomcat はバイトで動作します。コア コードは CoyoteAdapter.parsePathParameters() メソッドにありますが、ここでは公開されていません。 1.2 Cookieヘッダーから Cookie 解析をトリガーするメソッド呼び出しは次のとおりです。 CoyoteAdapter.service(リクエスト、レスポンス) └─CoyoteAdapter.postParseRequest(リクエスト、リクエスト、レスポンス、レスポンス) └─CoyoteAdapter.parseSessionCookiesId(リクエスト、リクエスト) └─Cookies.getCookieCount() └─Cookies.processCookies(MimeHeaders) └─Cookies.processCookieHeader(byte[], int, int) この processCookieHeader はバイトに対して動作し、解析は直感的ではないようです。Tomcat には、理解を助けるために文字列解析を使用する非推奨としてマークされたメソッドもあります。コードは次のとおりです。 プライベートvoid processCookieHeader(String cookieString){ // 複数の Cookie 値はカンマで区切られます StringTokenizer tok = new StringTokenizer(cookieString, ";", false); (tok.hasMoreTokens()) の間 { 文字列トークン = tok.nextToken(); // 等号の位置を取得します int i = token.indexOf("="); もし (i > -1) { // 名前と値を取得し、スペースを削除します。String name = token.substring(0, i).trim(); 文字列値 = token.substring(i+1, token.length()).trim(); // RFC 2109 およびバグにより両端の二重引用符が削除されました" 値 = stripQuote( 値 ); // 内部 Cookie キャッシュ プールから ServerCookie オブジェクトを取得します。 ServerCookie cookie = addCookie(); // 名前と値を設定する cookie.getName().setString(名前); cookie.getValue().setString(値); } それ以外 { // クッキーが不良です...そのままにしておきます } } } 解析後、次のステップは、parseSessionCookiesId メソッドで JSESSIONID という名前の Cookie をトラバースして一致させることです。存在する場合、その値はリクエストの requestedSessionId に設定され、内部セッション オブジェクトに関連付けられます。 2. セッションCookieを生成する セッションに関連する Cookie は Tomcat 自体によって生成されます。セッション オブジェクトを取得するために Servlet で Request.getSession() が使用されると、実行がトリガーされます。コア コードは次のとおりです。 保護されたセッションdoGetSession(boolean create) { ... // セッションインスタンスを作成する if (connector.getEmptySessionPath() && isRequestedSessionIdFromCookie()) { // セッション ID が Cookie から取得された場合は再利用し、URL から取得された場合はフィッシング攻撃の可能性を防ぐため再利用しないでください。session = manager.createSession(getRequestedSessionId()); } それ以外 { セッション = manager.createSession(null); } // セッションに基づいて新しいセッションCookieを作成する if ((セッション != null) && (getContext() != null) && getContext().getCookies()) { 文字列 scName = context.getSessionCookieName(); scName == nullの場合{ //デフォルトのJSESSIONID scName = Globals.SESSION_COOKIE_NAME; } // 新しいクッキーを作成する クッキー cookie = 新しい Cookie(scName, session.getIdInternal()); // パスドメインをセキュアに設定する セッションCookieを設定します。 // レスポンス ヘッダー フィールドに追加 response.addSessionCookieInternal(cookie, context.getUseHttpOnly()); } セッションが null の場合 セッション.アクセス(); 戻り値(セッション) } それ以外 { 戻り値 (null); } } レスポンスヘッダーフィールドに追加され、冒頭で説明した形式で Cookie オブジェクトに従って生成されます。 3. セッション Session は Tomcat 内のインターフェイスであり、HttpSession のファサード クラスであり、Web アプリケーションの特定のユーザーのリクエスト間の状態情報を維持するために使用されます。関連するクラス図の設計は次のとおりです。 主要なクラスまたはインターフェースの機能は次のとおりです。
この記事では、クラスター レプリケーションの原理は分析せず、スタンドアロン セッションの管理のみを分析します。 3.1 セッションの作成 最初に Request.getSession() を使用してサーブレット内のセッション オブジェクトを取得すると、StandardSession インスタンスが作成されます。 パブリックセッションcreateSession(String sessionId) { // デフォルトの戻り値は new StandardSession(this) インスタンス Session session = createEmptySession(); です。 // プロパティを初期化する session.setNew(true); セッションをtrueに設定します。 セッションの作成時間を設定します。 // セッションの有効期間を秒単位で設定します。デフォルト値は 30 分です。負の値は有効期限がないことを意味します。session.setMaxInactiveInterval(((Context) getContainer()).getSessionTimeout() * 60); セッションIDがnullの場合 // セッションIDを生成する セッションID = 生成セッションID(); セッションIDを設定します。 セッションカウンタ++; SessionTiming タイミング = new SessionTiming(session.getCreationTime(), 0); 同期 (セッション作成タイミング) { セッション作成タイミングを追加します。タイミングを指定します。 セッション作成タイミング.poll(); } 戻り値(セッション) } 鍵となるのは、セッションの一意の識別子の生成です。Tomcat の生成アルゴリズムを見てみましょう。
コアコードは次のとおりです。 保護された文字列generateSessionId() { バイトランダム[] = 新しいバイト[16]; 文字列 jvmRoute = getJvmRoute(); 文字列結果 = null; // 結果を 16 進数の文字列としてレンダリングします。StringBuffer buffer = new StringBuffer(); する { int 結果の長さバイト = 0; if (result != null) { // 繰り返し、再生成 buffer = new StringBuffer(); 重複++; } //sessionIdLengthは16です (resultLenBytes < this.sessionIdLength) の場合 { getRandomBytes(random); // ランダムに 16 バイトを取得します // デフォルトでは MD5 を使用して、これらの 16 バイトの要約を取得します ランダム = getDigest().digest(ランダム); // このバイト配列を走査し、最終的に 32 ビットの 16 進文字列を生成します。for (int j = 0; j < random.length && resultLenBytes < this.sessionIdLength; j++) { // 指定されたバイトの上位 4 ビットと下位 4 ビットを使用して 16 進文字を生成します。byte b1 = (byte) ((random[j] & 0xf0) >> 4); バイト b2 = (バイト) (ランダム[j] & 0x0f); // 16進数に変換 if (b1 < 10) {buffer.append((char) ('0' + b1));} // 16進文字を大文字に変換します。else {buffer.append((char) ('A' + (b1 - 10)));} b2 < 10 の場合 {buffer.append((char) ('0' + b2));} そうでない場合は{buffer.append((char) ('A' + (b2 - 10)));} 結果の長さバイト数++; } } jvmRoute != null の場合 {buffer.append('.').append(jvmRoute);} 結果 = buffer.toString(); } while (sessions.containsKey(result)); 返す(結果) } 3.2 セッション有効期限チェック 1 つの Web アプリケーションは 1 つのセッション マネージャーに対応します。つまり、StandardContext 内に Manager インスタンスが存在します。各コンテナ コンポーネントはバックグラウンド スレッドを開始し、定期的に自分自身と内部コンポーネントの backgroundProcess() メソッドを呼び出します。マネージャーのバックグラウンド処理は、セッションの有効期限が切れているかどうかを確認することです。 チェックのロジックは、すべてのセッションを取得し、それらの isValid を使用して期限切れかどうかを判断することです。コードは次のとおりです。 パブリックブール値isValid() { ... // アクティブかどうかを確認するかどうか。デフォルトは false ACTIVITY_CHECK && accessCount.get() > 0 の場合 { true を返します。 } // 時間が経過したかどうかを確認します if (maxInactiveInterval >= 0) { 長いtimeNow = System.currentTimeMillis(); int timeIdle = (int) ((timeNow - thisAccessedTime) / 1000L); (timeIdle >= maxInactiveInterval)の場合{ // 期限切れの場合は、内部処理を実行します // 主に期限切れイベントに関心のあるリスナーに通知します 有効期限が切れます(true); } } // 複数形は期限切れにならない return (this.isValid); } 3.3 セッションの永続性 永続性とは、メモリ内のアクティブなセッション オブジェクトをファイルにシリアル化するか、データベースに保存することを意味します。セッション管理コンポーネントが準拠しており、永続性が有効になっている場合、保存はライフサイクル イベントの停止メソッドで実行され、読み込みは開始メソッドで実行されます。 ファイルへの永続化。StandardManager は、ファイルへの永続化機能も提供します。セッション プール内のすべてのアクティブなセッションを CATALINA_HOME/work/Catalina/<host>/<webapp>/SESSIONS.ser ファイルに書き込みます。コードは doUnload メソッド内にあります。 FileStore は、ファイルへの永続化機能も提供します。StandardManager との違いは、各セッションを <id>.session という名前の単一のファイルに書き込むことです。 データベースに永続化し、シリアル化されたバイナリ データを含むセッション関連データをテーブルに保存します。テーブル フィールド情報は次のとおりです。 tomcat_sessionsテーブルを作成する( session_id varchar(100) NULLでない主キー、 valid_session char(1) not null, -- 有効期間 max_inactive int not null, -- 最大有効期間 last_access bigint not null, -- 最終アクセス時間 app_name varchar(255), -- アプリケーション名(/Engine/Host/Context 形式) session_data mediumblob、--バイナリデータ KEY kapp_name (app_name) ); 注:データベース ドライバーの jar ファイルを $CATALINA_HOME/lib ディレクトリに配置して、Tomcat 内のクラス ローダーから見えるようにする必要があります。 4. まとめ この記事では、Tomcat のセッション管理について簡単に分析します。もちろん、多くの詳細は無視されています。興味のある方は、ソース コードを詳しく調べてください。Tomcat クラスター セッションの実装については、後で分析します。 要約する 以上がこの記事の全内容です。この記事の内容が皆様の勉強や仕事に何らかの参考学習価値をもたらすことを願います。123WORDPRESS.COM をご愛顧いただき、誠にありがとうございます。 以下もご興味があるかもしれません:
|
<<: Windows 環境に mysql-8.0.11-winx64 をインストールする際に発生する問題を解決する
>>: JavaScriptはフォームデータの非同期取得を実装します
dom要素に新しい子要素を追加し、新しく追加された新しい要素がコンテナーのスコープを超えた場合は、次...
目次序文1. Nginx+Tomcat 2. Nginxサーバーを構成する3. Tomcatアプリケ...
目次1. 関数を使用してコンポーネントを作成する2. クラスを使用してコンポーネントを作成する3. ...
Linux コマンドの学習は、ほとんどの初心者にとって最大の障害です。今日は、Linux システムで...
目次序文問題を見つける解決する追記序文最近、 UIコンポーネントを作成する予定で、 vue 2.xと...
CSS は、スクロールを許可しながらスクロール バーを非表示にするために Overflow を設定し...
目次1. 背景2. テーブルロックによるクエリの遅延3. オンラインでテーブル構造を変更するとどのよ...
背景今日、CodePen を閲覧していたところ、非常に興味深い効果を見つけました。 CodePen ...
Navicat がエクスポートしたデータはインポートできません。最後に、MySQLコマンドのインポー...
目次1. 依存関係をインストールする2. vue.config.js ファイルで pwa を設定しま...
IDEA 2020 で Tomcat を構成する手順は次のとおりです。最初のステップはTomcatを...
圧縮アップロード画像、スクラッチカード、ポスター作成、チャートプラグインなど、フロントエンド開発にお...
よく遭遇する問題: 下部の要素を「下部に貼り付ける」効果を CSS でどのように実現するか。この記事...
一般的に、テーブルを使用する場合は、常に <table border="1"...
サンプルコード: java.util.Random をインポートします。 java.util.UUI...