Servlet APIにおけるHttpSessionの挙動検証
Javaでよくあるセッション管理の仕組みについて他人に説明している時に、どうも自分の認識があいまいになっていることに気付いたので、挙動を検証してみます。よくあるセッション管理ということで、Servlet APIにおけるHttpSessionの挙動を検証します。
検証するWebアプリケーション
アクセスするとcount=1
というボディを返し、更にアクセスするとcount=2
、count=3
とカウントアップするだけのWebアプリケーションです。もちろん、異なるWebブラウザからアクセスした場合はcount=1
からやり直しです。Webブラウザごとにセッション管理を行い、カウントを保持します。
検証のために作成したWebアプリケーションは、次のリポジトリにあります。検証では詳細に説明はしないので、READMEやソースコードをご覧ください。
検証
セッション・タイムアウトを何も設定しない場合
セッション・タイムアウトはsrc/main/webapp/WEB-INF/web.xml
の<session-timeout>
で設定しますが、まずはweb.xml
を削除してデフォルトの挙動を確認してみます。
Webブラウザを開いてhttp://localhost:8080/にアクセスすると、count=1
が表示されます。この時、レスポンスにSet-Cookie
にJSESSIONID
が設定されます。Expires
やMax-Age
が未設定なので、このJSESSIONID
はWebブラウザを閉じたときにWebブラウザから削除されます。
次にアクセスすると、count=2
が表示されます。この時、リクエストに先ほどのJSESSIONID
が設定されています。このJSESSIONID
により先ほどと同一セッションと判定されて、サーバー側でカウントアップ処理が行われます。
Webブラウザを閉じてアクセスすると、count=1
が表示されます。この時、リクエストにはJSESSIONID
が設定されておらず、レスポンスにSet-Cookie
で新しいJSESSIONID
が設定されます。上で説明した通り、Webブラウザを閉じたためにJSESSIONID
がWebブラウザから削除され、このような挙動になります。
なお、Webアプリケーション側はセッションを無期限で保持します。
セッション・タイムアウトを設定した場合
セッション・タイムアウトを1分に設定した時の挙動を確認してみます。
まず、web.xml
を次のように修正します。
<session-config>
<session-timeout>1</session-timeout>
</session-config>
<session-timeout>
は、タイムアウト時間を分単位で設定します。
Webブラウザを開いてhttp://localhost:8080/にアクセスすると、先ほどと同様にcount=1
が表示されます。レスポンスも先ほどと同様にSet-Cookie
でJSESSIONID
が設定されており、Expires
やMax-Age
が未設定なのでWebブラウザを閉じたときに削除されます。
次に1分以内にアクセスすると、count=2
が表示されます。同様にアクセスし続けると、カウントアップされ続けます。Webアプリケーション側のセッション・タイムアウト時刻は、アクセスするたびにリセットされます。
次に1分以上後にアクセスすると、count=1
が表示されます。リクエストを見るとJSESSIONID
が設定されていますが、レスポンスを見るとSet-Cookie
でリクエストとは異なるJSESSIONID
が設定されています。つまり、Webアプリケーション側でセッションが破棄され、新しいセッションが開始されたということです。
なお、1分以内にWebブラウザを閉じて再びアクセスしてもcount=1
が表示されます。これは、Webブラウザを閉じたためにJSESSIONID
が削除されたためです。
Cookie寿命を設定した場合
セッション・タイムアウトを1分、Cookie寿命を2分に設定した時の挙動を確認してみます。
まず、web.xml
を次のように修正します。
<session-config>
<session-timeout>1</session-timeout>
<cookie-config>
<max-age>120</max-age>
</cookie-config>
</session-config>
<cookie-config>/<max-age>
は、Cookie寿命を秒単位で設定します。これを設定することで、Set-Cookie
にExpires
とMax-Age
が設定されるようになります。
セッション・タイムアウトは、Webアプリケーションにアクセスするごとにタイムアウト時刻が更新されます。これに対してCookie寿命は、最初にSet-Cookie
されたときに設定されそのあとは更新されないために、寿命の時刻が来るとWebブラウザから削除されます。Set-Cookie
にExpires
とMax-Age
が設定されるためにWebブラウザを閉じても削除されないため、Webブラウザのライフサイクルをまたいでセッションを保持することができます。
実際の挙動を確認してみます。Webブラウザを開いてhttp://localhost:8080/にアクセスすると、これまでと同様にcount=1
が表示されます。レスポンスにSet-Cookie
でJSESSIONID
が設定されますが、先ほどと異なりExpires
とMax-Age
が設定されます。
1分以内に同様にアクセスすると、カウントアップされ続けます。
Webブラウザを更新し続けていると、最初のアクセスから2分経過後にcount=1
に戻ります。リクエストを見るとそれまで設定されていたJSESSIONID
が設定されておらず、リクエストにJSESSIONID
がないのでレスポンスのSet-Cookie
で新しいJSESSIONID
が設定されます。
なお、1分以内にWebブラウザを閉じて再びアクセスした場合、閉じる前のセッションが保持されているためにカウントアップが継続されます。
おわりに
どのようにタイムアウトするのか、通信がどのように行われるのか認識があいまいでしたが、整理できました。次はSpring SessionやSpring Securityにおけるセッション管理を検証してみたいと思います。