Servlet APIにおけるHttpSessionの挙動検証

Updated: / Reading time: 4 minutes

Javaでよくあるセッション管理の仕組みについて他人に説明している時に、どうも自分の認識があいまいになっていることに気付いたので、挙動を検証してみます。よくあるセッション管理ということで、Servlet APIにおけるHttpSessionの挙動を検証します。

検証するWebアプリケーション

アクセスするとcount=1というボディを返し、更にアクセスするとcount=2count=3とカウントアップするだけのWebアプリケーションです。もちろん、異なるWebブラウザからアクセスした場合はcount=1からやり直しです。Webブラウザごとにセッション管理を行い、カウントを保持します。

PlantUML SVG diagram

検証のために作成したWebアプリケーションは、次のリポジトリにあります。検証では詳細に説明はしないので、READMEやソースコードをご覧ください。

検証

セッション・タイムアウトを何も設定しない場合

セッション・タイムアウトはsrc/main/webapp/WEB-INF/web.xml<session-timeout>で設定しますが、まずはweb.xmlを削除してデフォルトの挙動を確認してみます。

Webブラウザを開いてhttp://localhost:8080/にアクセスすると、count=1が表示されます。この時、レスポンスにSet-CookieJSESSIONIDが設定されます。ExpiresMax-Ageが未設定なので、このJSESSIONIDはWebブラウザを閉じたときにWebブラウザから削除されます。

default timeout 01

次にアクセスすると、count=2が表示されます。この時、リクエストに先ほどのJSESSIONIDが設定されています。このJSESSIONIDにより先ほどと同一セッションと判定されて、サーバー側でカウントアップ処理が行われます。

default timeout 02

Webブラウザを閉じてアクセスすると、count=1が表示されます。この時、リクエストにはJSESSIONIDが設定されておらず、レスポンスにSet-Cookieで新しいJSESSIONIDが設定されます。上で説明した通り、Webブラウザを閉じたためにJSESSIONIDがWebブラウザから削除され、このような挙動になります。

default timeout 03

なお、Webアプリケーション側はセッションを無期限で保持します。

セッション・タイムアウトを設定した場合

セッション・タイムアウトを1分に設定した時の挙動を確認してみます。

まず、web.xmlを次のように修正します。

<session-config>
    <session-timeout>1</session-timeout>
</session-config>

<session-timeout>は、タイムアウト時間を分単位で設定します。

Webブラウザを開いてhttp://localhost:8080/にアクセスすると、先ほどと同様にcount=1が表示されます。レスポンスも先ほどと同様にSet-CookieJSESSIONIDが設定されており、ExpiresMax-Ageが未設定なのでWebブラウザを閉じたときに削除されます。

session timeout 01

次に1分以内にアクセスすると、count=2が表示されます。同様にアクセスし続けると、カウントアップされ続けます。Webアプリケーション側のセッション・タイムアウト時刻は、アクセスするたびにリセットされます。

session timeout 02

次に1分以上後にアクセスすると、count=1が表示されます。リクエストを見るとJSESSIONIDが設定されていますが、レスポンスを見るとSet-Cookieでリクエストとは異なるJSESSIONIDが設定されています。つまり、Webアプリケーション側でセッションが破棄され、新しいセッションが開始されたということです。

session timeout 03

なお、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-CookieExpiresMax-Ageが設定されるようになります。

セッション・タイムアウトは、Webアプリケーションにアクセスするごとにタイムアウト時刻が更新されます。これに対してCookie寿命は、最初にSet-Cookieされたときに設定されそのあとは更新されないために、寿命の時刻が来るとWebブラウザから削除されます。Set-CookieExpiresMax-Ageが設定されるためにWebブラウザを閉じても削除されないため、Webブラウザのライフサイクルをまたいでセッションを保持することができます。

実際の挙動を確認してみます。Webブラウザを開いてhttp://localhost:8080/にアクセスすると、これまでと同様にcount=1が表示されます。レスポンスにSet-CookieJSESSIONIDが設定されますが、先ほどと異なりExpiresMax-Ageが設定されます。

cookie max age 01

1分以内に同様にアクセスすると、カウントアップされ続けます。

cookie max age 02

Webブラウザを更新し続けていると、最初のアクセスから2分経過後にcount=1に戻ります。リクエストを見るとそれまで設定されていたJSESSIONIDが設定されておらず、リクエストにJSESSIONIDがないのでレスポンスのSet-Cookieで新しいJSESSIONIDが設定されます。

cookie max age 03

なお、1分以内にWebブラウザを閉じて再びアクセスした場合、閉じる前のセッションが保持されているためにカウントアップが継続されます。

おわりに

どのようにタイムアウトするのか、通信がどのように行われるのか認識があいまいでしたが、整理できました。次はSpring SessionやSpring Securityにおけるセッション管理を検証してみたいと思います。