
サーブレット&JSPの基本|セッションスコープのしくみ
ブラウザごとに情報を見分ける。セッションIDとクッキーでセッションスコープの裏側を理解しよう
セッションスコープを使うと、リクエストをまたいでインスタンスを利用できます。
たとえば、研修コース申込機能であれば、入力画面で入力された申込情報をセッションスコープに保存し、確認画面や完了処理でも同じインスタンスを利用できます。
リクエストスコープでは、レスポンスが返ると保存したインスタンスが消えてしまいます。そのため、次のリクエストでは取得できません。
一方、セッションスコープでは、レスポンス後もインスタンスを残せます。これにより、複数の画面をまたいで同じ情報を扱えるようになります。
では、アプリケーションサーバは、どのブラウザにどのセッションスコープを対応させているのでしょうか。
同じWebアプリケーションに複数の利用者がアクセスしていても、Aさんの情報はAさんだけに見え、Bさんの情報はBさんだけに見えます。ショッピングカートの中身やログイン中のユーザー情報が、他の利用者と混ざらないのは、この仕組みがあるためです。
この記事では、セッションスコープの裏側で使われているセッションID、クッキー、セッションタイムアウト、removeAttributeによる削除、invalidateによるセッション破棄について解説します。
セッションスコープはブラウザごとに用意される
セッションスコープの正体は、HttpSessionインスタンスです。
このHttpSessionインスタンスは、利用者のブラウザごとに作成されます。
より具体的には、そのブラウザに対して最初にrequest.getSessionが実行されたタイミングで、アプリケーションサーバがHttpSessionインスタンスを作成します。
このとき、アプリケーションサーバはセッションIDという識別番号も発行します。
セッション作成時に行われること
| 項目 | 内容 |
|---|---|
| HttpSessionインスタンスの作成 | ブラウザごとのセッションスコープを用意する |
| セッションIDの発行 | ブラウザを区別するためのIDを作成する |
| セッションIDの設定 | HttpSessionインスタンスとブラウザに対応づける |
セッションIDは、ブラウザとサーバの間で、このブラウザはどのセッションスコープを使うのかを判断するための目印です。
この目印があることで、利用者ごとに別々のセッションスコープを使えるようになります。
セッションIDで利用者を区別する
セッションIDは、利用者のブラウザを区別するためのIDです。
たとえば、同じWebアプリケーションに青山さんと山田さんがアクセスしているとします。
青山さんのブラウザにはID:00001が設定され、山田さんのブラウザにはID:00002が設定されます。
アプリケーションサーバ側には、それぞれのIDに対応するHttpSessionインスタンスが用意されます。
セッションIDとセッションスコープの対応
| ブラウザ | セッションID | 対応するセッションスコープ |
|---|---|---|
| 青山さんのブラウザ | ID:00001 | 青山さん用のHttpSession |
| 山田さんのブラウザ | ID:00002 | 山田さん用のHttpSession |
ブラウザは、以降のリクエストで自分に設定されたセッションIDをサーバへ送信します。
サーバは受け取ったセッションIDを確認し、そのIDに対応するHttpSessionインスタンスを取り出します。
この仕組みによって、青山さんは青山さん用のセッションスコープを使い、山田さんは山田さん用のセッションスコープを使えるようになります。
図1:セッションIDによるブラウザの区別

この図から分かること
セッションスコープは、利用者のブラウザごとに用意されます。
アプリケーションサーバは、ブラウザに設定されたセッションIDをもとに、どのHttpSessionインスタンスを使うかを判断します。
青山さんのブラウザからID:00001が送られてきた場合は、ID:00001に対応するセッションスコープを使います。山田さんのブラウザからID:00002が送られてきた場合は、ID:00002に対応するセッションスコープを使います。
この仕組みにより、ログイン情報やカート情報のような利用者ごとの情報が、他の利用者と混ざらずに管理されます。
request.getSessionとセッションIDの関係
サーブレットでセッションスコープを使うときは、request.getSessionでHttpSessionインスタンスを取得します。
最初にrequest.getSessionが実行されたとき、まだそのブラウザ用のセッションがなければ、アプリケーションサーバが新しいHttpSessionインスタンスを作成します。
同時に、そのHttpSessionを識別するためのセッションIDも発行されます。
2回目以降のリクエストでは、ブラウザから送られてきたセッションIDをもとに、同じHttpSessionインスタンスを取得します。
getSession実行時の動き
| タイミング | 動き |
|---|---|
| 初回のgetSession | 新しいHttpSessionを作成し、セッションIDを発行する |
| 2回目以降のgetSession | 送られてきたセッションIDに対応するHttpSessionを取得する |
この動きにより、同じブラウザからの連続したリクエストでは、同じセッションスコープを利用できます。
セッションスコープに保存したインスタンスを次のリクエストでも取得できるのは、セッションIDによって同じHttpSessionが見つけられるからです。
セッションIDはブラウザから自動送信される
セッションIDは、リクエストのたびにサーバへ送信されます。
ただし、開発者が毎回プログラムでセッションIDを送信する処理を書くわけではありません。
このやりとりは、ブラウザとサーバの裏側で自動的に行われます。
そこで使われる代表的な仕組みがクッキーです。
クッキーを使うことで、サーバはブラウザに小さなデータを保存させることができます。セッションIDも、このクッキーを使ってブラウザ側に保持されることがあります。
クッキーとは
クッキーとは、Webサーバやアプリケーションサーバが、ブラウザにデータを保存させるための仕組みです。
サーバがレスポンスにクッキーを含めると、ブラウザはそのクッキーを保存します。
その後、同じサーバへアクセスするとき、ブラウザは保存しているクッキーをHTTPリクエストに付けて自動的に送信します。
クッキーの基本的な流れ
| 順番 | 内容 |
|---|---|
| 1 | サーバがレスポンスにクッキーを含める |
| 2 | ブラウザがクッキーを保存する |
| 3 | 次回以降のリクエストでブラウザがクッキーを送信する |
| 4 | サーバがクッキー内の情報を確認する |
アプリケーションサーバは、このクッキーにセッションIDを含めることで、ブラウザとサーバの間でセッションIDをやりとりします。
開発者が毎回セッションIDを送信するコードを書かなくても、ブラウザが自動的にセッションIDを送信してくれるのは、クッキーの仕組みが使われているためです。
図2:クッキーを使ったセッションIDのやりとり

この図から分かること
サーバは、初回のアクセス時にHttpSessionインスタンスを作成し、セッションIDを発行します。
そのセッションIDは、レスポンスに含まれるクッキーとしてブラウザへ送られます。ブラウザはクッキーを保存し、次回以降のリクエストで自動的にサーバへ送信します。
サーバは送られてきたセッションIDを確認し、対応するセッションスコープを取得します。
この仕組みによって、同じブラウザからのリクエストを、同じ利用者の操作として扱えるようになります。
クッキーには有効期限がある
クッキーには有効期限を設定できます。
有効期限が設定されているクッキーは、その期限内であればブラウザを閉じても残ることがあります。新しくブラウザを開いたあとでも、同じサーバへアクセスすると、保存されているクッキーが送信されます。
そのため、有効期限内のセッションIDが残っていれば、ブラウザを閉じ直してもセッションスコープを継続して利用できる場合があります。
ただし、特別な設定をしない限り、アプリケーションサーバはブラウザが閉じられるまでをセッションIDの有効期限とすることが一般的です。
その場合、ブラウザを閉じると、同じセッションスコープを再利用できなくなります。
クッキーの有効期限とセッション
| 状況 | セッションスコープの扱い |
|---|---|
| ブラウザを開いたまま同じサイトへアクセスする | 同じセッションIDが送られ、同じセッションスコープを使える |
| ブラウザを閉じるまでが有効期限の場合 | ブラウザを閉じると同じセッションを利用できなくなる |
| 有効期限が長く設定されている場合 | ブラウザを閉じてもクッキーが残ることがある |
ショッピングサイトで、ブラウザを閉じたあとにカートの内容が消えてしまうことがあります。
これは、ブラウザを閉じたことでセッションIDを保持できなくなり、前回のセッションスコープを利用できなくなったためです。
ブラウザを閉じてもカートの内容が残るサイトでは、クッキーの有効期限を調整したり、セッションスコープ以外の方法でデータを保存したりしている場合があります。
複数ウィンドウではセッションIDが共有されることがある
ブラウザのウィンドウを複数開いて動作確認するときは注意が必要です。
多くのブラウザでは、同じブラウザで開いている複数のウィンドウが、同じセッションIDを共有します。
そのため、あるウィンドウでセッションスコープに保存した情報が、別のウィンドウでも利用されることがあります。
複数ウィンドウで起こりやすいこと
| 状況 | 起こること |
|---|---|
| 1つ目のウィンドウで申込情報を保存する | セッションスコープに情報が残る |
| そのウィンドウを残したまま別ウィンドウで再実行する | 同じセッションIDが使われることがある |
| 空のセッションを想定している | 前回の情報が残っていて想定と違う動きになることがある |
開発中に、セッションスコープを使ったプログラムの動きがおかしいと感じた場合は、ブラウザのウィンドウをすべて閉じてから実行し直すと確認しやすくなります。
セッションスコープは便利ですが、前回の情報が残ることがあるため、動作確認ではセッションの状態を意識することが大切です。
セッションスコープの内容は自動ではすぐに消えない
セッションスコープは、リクエストをまたいでインスタンスを保持できる便利な仕組みです。
しかし、便利だからといって必要以上に使いすぎると、アプリケーションサーバのメモリを圧迫する原因になります。
リクエストスコープは、レスポンスが返されると役目を終えます。
一方、HttpSessionインスタンスは、使われなくなったように見えても、すぐにはサーバから消えません。
サーバ側から見ると、利用者がブラウザを閉じたのか、少し席を外しているだけなのかを正確に判断できないためです。
HttpSessionがすぐに消えない理由
| 理由 | 内容 |
|---|---|
| 利用者の状態が分からない | サーバは利用者が戻ってくるかどうか判断できない |
| ブラウザを閉じたことをすぐに検知しにくい | サーバ側では不要になったか分かりにくい |
| 次のリクエストに備える必要がある | 同じセッションを再利用する可能性がある |
そのため、HttpSessionインスタンスは、通常のインスタンスのようにすぐガベージコレクションの対象になるとは限りません。
セッションスコープは便利ですが、長く残る分だけ管理も重要になります。
セッションタイムアウトとは
HttpSessionインスタンスをいつまでもサーバ内に残しておくと、メモリ不足の原因になります。
そこで、アプリケーションサーバは、一定時間利用されていないHttpSessionインスタンスを不要と判断し、破棄できるようにします。
これをセッションタイムアウトといいます。
たとえば、しばらく操作しないまま一定時間が経過すると、そのセッションは無効になります。Webサイトで30分以上操作しないと無効になりますといった案内を見かけることがありますが、これはセッションタイムアウトに関係しています。
Apache Tomcatでは、セッションタイムアウトまでの時間が初期設定で30分になっています。
セッションタイムアウトの考え方
| 項目 | 内容 |
|---|---|
| 対象 | 一定時間利用されていないHttpSession |
| 目的 | 不要なセッションを残し続けないようにする |
| 結果 | 対象のHttpSessionが破棄される |
| Tomcatの初期設定 | 30分 |
セッションタイムアウトがあることで、利用されなくなったHttpSessionインスタンスをいつまでも保持し続けることを防げます。
ただし、タイムアウトを待てばよいという考え方だけでは不十分です。
図3:セッションタイムアウトと開発者による削除

この図から分かること
セッションスコープに保存したインスタンスは、リクエストスコープより長く残ります。
そのため、使われなくなったHttpSessionインスタンスは、一定時間が経過するとセッションタイムアウトによって破棄されます。
ただし、タイムアウトを待つだけではなく、開発者が不要になったインスタンスをremoveAttributeで削除したり、ログアウト時などにinvalidateでセッションスコープそのものを破棄したりすることも大切です。
セッションスコープを使いすぎるとメモリを圧迫する
セッションスコープに保存したインスタンスは、レスポンス後も残ります。
これは便利な反面、多くの利用者がアクセスし、それぞれのセッションスコープに大量のデータを保存すると、アプリケーションサーバのメモリを消費します。
短時間にアクセスが集中した場合、セッションタイムアウトやガベージコレクションによる後片付けが間に合わないこともあります。
セッションスコープの多用で起こりやすい問題
| 問題 | 内容 |
|---|---|
| メモリ使用量が増える | 利用者ごとのHttpSessionが残り続ける |
| 性能が低下する | サーバが多くのインスタンスを管理する必要がある |
| サーバ停止の原因になる | メモリ不足が深刻になる場合がある |
| 古い情報が残る | 不要なインスタンスが次の処理に影響することがある |
セッションスコープは、リクエストをまたいで本当に必要な情報を保存するために使います。
何でもセッションスコープに入れるのではなく、保存する必要があるか、いつ削除するかを意識することが大切です。
不要になったインスタンスはremoveAttributeで削除する
セッションスコープに保存したインスタンスが不要になったら、removeAttributeで削除します。
たとえば、研修コース申込機能では、確認画面から申込を実行したあと、申込情報をセッションスコープに残しておく必要はありません。
そのため、申込完了時にentryUserをremoveAttributeで削除します。
removeAttributeを使う場面
| 場面 | 内容 |
|---|---|
| 申込処理が完了した | 申込情報を削除する |
| 一時的に保存した情報を使い終えた | 不要な属性を削除する |
| 古い情報を次の処理に残したくない | 属性名を指定して削除する |
removeAttributeは、セッションスコープの中に保存されている特定のインスタンスだけを削除します。
セッションスコープそのものは残ります。
セッションスコープそのものを破棄する
保存している一部のインスタンスではなく、セッションスコープ全体を破棄したい場合は、invalidateを使います。
invalidateを実行すると、HttpSessionインスタンスそのものが破棄されます。
そのセッションスコープに保存されていたすべてのインスタンスも利用できなくなります。
invalidateの特徴
| 項目 | 内容 |
|---|---|
| 目的 | セッションスコープ全体を破棄する |
| 消えるもの | セッションスコープに保存されていたすべてのインスタンス |
| よく使う場面 | ログアウト処理 |
| 実行後 | 次にgetSessionを実行すると新しいHttpSessionが作成される |
ログアウト処理では、ログイン中の利用者情報や、セッションスコープに保存された関連情報をすべて消したいことがあります。
このような場合は、個別にremoveAttributeで削除するよりも、invalidateでセッションスコープ全体を破棄するほうが適しています。
ログアウト時にセッションを破棄する例
ここでは、ログアウト処理でセッションスコープ全体を破棄するサーブレットを例にします。
ログイン中の学習者情報や、申込中の情報などをセッションスコープに保存している場合、ログアウト時にまとめて破棄します。
セッションスコープを破棄するサーブレットの例
package servlet;
import java.io.IOException;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
@WebServlet("/LogoutServlet")
public class LogoutServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
// HttpSessionインスタンスを取得
HttpSession session = request.getSession();
// セッションスコープそのものを破棄
session.invalidate();
// ログアウト後の画面へリダイレクト
response.sendRedirect("TrainingEntryServlet");
return;
}
}この例では、request.getSessionでHttpSessionインスタンスを取得し、session.invalidateでセッションスコープ全体を破棄しています。
その後、TrainingEntryServletへリダイレクトしています。
ログアウト後は、以前のセッションスコープに保存されていたインスタンスは利用できません。次にrequest.getSessionが実行されると、新しいHttpSessionインスタンスが作成されます。
removeAttributeとinvalidateの使い分け
removeAttributeとinvalidateは、どちらもセッションスコープ内の情報を整理するために使います。
ただし、削除する範囲が違います。
removeAttributeとinvalidateの違い
| 操作 | 削除する範囲 | 使う場面 |
|---|---|---|
| removeAttribute | 指定した属性名のインスタンスだけ | 申込完了後にentryUserだけ削除する |
| invalidate | セッションスコープ全体 | ログアウト時にすべての情報を破棄する |
removeAttributeは、セッションスコープ内の特定のインスタンスだけを削除したいときに使います。
invalidateは、セッションスコープそのものを破棄したいときに使います。
どちらも、不要になった情報を残さないための大切な操作です。
セッションスコープの管理で意識したいこと
セッションスコープは、リクエストをまたいでデータを保持できるため、Webアプリケーションの幅を広げてくれます。
しかし、長く残るという特徴があるため、管理しないまま使い続けると問題が起こることがあります。
管理で意識したいポイント
| 確認項目 | 内容 |
|---|---|
| 本当にセッションスコープが必要か | 1回の表示だけならリクエストスコープで十分な場合がある |
| いつ保存するか | ログイン時、入力完了時など、保存タイミングを決める |
| いつ削除するか | 完了時、キャンセル時、ログアウト時など、削除タイミングを決める |
| 何を保存するか | 必要な情報だけを保存する |
| どの属性名で保存するか | 取得や削除と対応しやすい名前にする |
セッションスコープは、保存できるから何でも入れる場所ではありません。
リクエストをまたいで使う必要がある情報だけを保存し、不要になったタイミングで削除または破棄することが大切です。
セッションスコープとステートフルな通信
HTTPは、基本的には前回のリクエストの状態を覚えておく仕組みを持っていません。
つまり、何もしなければ、1回目のリクエストと2回目のリクエストは別々のものとして扱われます。
このように、リクエストをまたいで情報を保持しない通信をステートレスな通信といいます。
一方、リクエストをまたいでユーザーの情報を保持する通信をステートフルな通信といいます。
セッションスコープは、HTTP上でステートフルな動きを実現するための仕組みの1つです。
ステートレスとステートフル
| 種類 | 内容 |
|---|---|
| ステートレスな通信 | リクエストをまたいで情報を保持しない |
| ステートフルな通信 | リクエストをまたいで情報を保持する |
セッションスコープを使えば、ログイン中の利用者情報や、画面遷移中の申込情報などを保持できます。
その結果、複数のリクエストを1つの流れとして扱えるようになります。
セッションスコープ以外の方法
リクエストをまたいで情報を扱う方法は、セッションスコープだけではありません。
リクエストパラメータやクッキーを使って、状態を引き継ぐこともできます。
状態を引き継ぐ方法
| 方法 | 考え方 |
|---|---|
| セッションスコープ | サーバ側のHttpSessionにインスタンスを保存する |
| リクエストパラメータ | URLやフォームに値を含めて次のリクエストへ送る |
| クッキー | ブラウザ側に情報を保存し、次回以降のリクエストで送信する |
どの方法を使うかは、扱う情報の内容や、どのくらいの期間保持したいかによって変わります。
この段階では、セッションスコープはサーバ側でユーザーごとの情報を保持する仕組みであり、その識別にセッションIDとクッキーが関わっている、と押さえておきましょう。
セッションスコープのしくみで確認したいこと
セッションスコープを使うときは、表面的な保存や取得だけでなく、裏側のしくみも意識すると理解が深まります。
確認したいポイント
| 確認項目 | 内容 |
|---|---|
| セッションスコープの正体 | HttpSessionインスタンス |
| 作成タイミング | 最初にrequest.getSessionを実行したとき |
| 利用者の区別 | セッションIDでブラウザを区別する |
| セッションIDのやりとり | クッキーを使って自動的に行われる |
| 複数ウィンドウ | 同じブラウザではセッションIDを共有することがある |
| タイムアウト | 一定時間使われないHttpSessionは破棄される |
| 個別削除 | removeAttributeで特定のインスタンスを削除する |
| 全体破棄 | invalidateでセッションスコープ全体を破棄する |
セッションスコープは、リクエストをまたいで同じ情報を使うための便利な仕組みです。
その裏側では、ブラウザごとに発行されたセッションIDと、それをやりとりするクッキーが働いています。
便利な一方で、サーバ側にインスタンスを残す仕組みでもあるため、不要になった情報はremoveAttributeで削除し、ログアウトのようにセッション全体が不要になった場合はinvalidateで破棄することを意識しましょう。
