セッション管理

Revised: 7th/July/2002

セッションとは何か

HTTP は stateless と呼ばれる、要求/応答がワンセットごとに独立するように設計されています。これによって、途中でネットワークが切断されても、次回の通信に全く影響を及ぼしません。

要求1: こんにちは。菅井です。
応答1: いらっしゃい、菅井さん。
要求2: ハッピーですか?
応答2: いえ、あまり。ところで、お名前は?

これがステートレスと言うことです。サーバ側では、最初の要求/応答と、二回目の要求/応答が完全に独立しており、セッションになりません。一連の要求/応答をトラッキングするには、その上に乗るアプリケーション側で実装する必要があります。

セッションは同一ユーザからの一連のアクセスを指し、セッション管理はユーザを識別する仕組みです。前回のアクセス時の状況を保持して、次回以降のアクセス時にユーザを識別した処理ができます。

例えば、次のような、一連の処理を継続して処理するために使われます。

  1. ログイン認証し、
  2. ショッピングカートに商品を入れて、
  3. 会計処理をして、
  4. ログアウトする。

ログイン認証から、ログアウトするまで、サーバ側では同一ユーザからのアクセスであることを認識して特定する必要があります。これを行うのがセッション管理です。

セッションは、cookie や URL への埋め込みによって実現しますが、一般に煩雑な作業になります。 Java では、セッション管理の仕組みを言語仕様として持っており、実装方法に無自覚でいられます。 HttpSession インタフェースを使うと、サーブレット・コンテナが自動的にセッション管理を行ってくれます。

サンプル

ドキュメント・ルートの設定

面倒ですが、これも練習です。今回もドキュメント・ルートを作ってみましょう。

server.xml

ドキュメント・ルートを Tomcat に認識させるには、Tomcat がインストールされたディレクトリの、 conf/server.xml になります。

202 行目付近に次のようなコードがあります。

        <!-- Tomcat Manager Context -->
        <Context path="/manager" docBase="manager"
         debug="0" privileged="true"></Context>

このコードの次の行から、次のようなコードを記述します。

        <!-- Session Examples Context -->
        <Context path="/session" docBase="C:/java/session" debug="0"
                 reloadable="true" crossContext="true"/>

ドキュメント・ルート C:\java\session が、コンテキスト・ルート /session にマッピングされました。 localhost の場合は、 URL http://localhost:8080/session からアクセスできるようになりました。

ディレクトリ構造

server.xml で設定したドキュメント・ルートに、次のディレクトリ構造を作成します。

C:\java\session以下のディレクトリ構造
図: C:\java\session 以下のディレクトリ構造

web.xml

ここでは、サーブレットに別名をつけて、アクセスするための URL パターンにマッピングしておきます。この情報はドキュメント・ルート C:\java\sessionDemoWEB-INF\web.xml に記述します。

今から、サーブレット SessionDemo を作成し、ドキュメント・ルートの WEB-INF\classes に配置します。このサーブレットに、session という別名を与えて、 URL http://localhost:8080/session/demo からアクセスできるように設定します。

C:\java\sessionDemo\WEB-INF\web.xml を次のように作成します。

<?xml version="1.0" encoding="Shift_JIS"?>
<!DOCTYPE web-app
    PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
    "http://java.sun.com/dtd/web-app_2_3.dtd">

<web-app>
	<!-- サーブレット名 -->
	<servlet>
		<servlet-name>session</servlet-name>
		<servlet-class>SessionDemo</servlet-class>
	</servlet>

	<!-- URL パターン -->
	<servlet-mapping>
		<servlet-name>session</servlet-name>
		<url-pattern>/demo</url-pattern>
	</servlet-mapping>
</web-app>
web.xmlの配備
図: web.xml の配備

サーブレット

ドキュメント・ルート C:\java\sessionDemoWEB-INF\classes に次のようなコードを用意してコンパイルしておきます。

SessionDemo.javaの配備
図: SessionDemo.java の配備

SessionDemo.java:

import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

public class SessionDemo extends HttpServlet {

	public void doGet(HttpServletRequest request, HttpServletResponse response)
		throws ServletException, IOException {
		doPerform(request, response);
	}

	public void doPost(HttpServletRequest request, HttpServletResponse response)
		throws ServletException, IOException {
		doPerform(request, response);
	}

	public void doPerform(HttpServletRequest request, HttpServletResponse response)
		throws ServletException, IOException {

		/*  セッションの開始
		 *  セッション情報を調べて、存在しなければ作成
		 */
		HttpSession session = request.getSession(true);

		int cnt;
		String msg, id;
		// セッションIDの取得
		id = session.getId();

		try {
			// セッションに格納された値の取得
			String cntStr = (String)session.getAttribute("counter");
			cnt = Integer.parseInt(cntStr);
			msg = cnt + " 回目のお越しです!";
		} catch (NumberFormatException e) {
			cnt = 1;
			msg = "はじめまして!";
		}
		cnt++;
		// セッションに値を格納
		session.setAttribute("counter", Integer.toString(cnt));

		// 応答文字コードのセット
		response.setContentType("text/html; charset=Shift_JIS");
		// 出力ストリームの取得
		PrintWriter out = response.getWriter();
		out.println("<html><head>\n"
			+ "<meta http-equiv=\"content-type\" content=\"text/html; charset=Shift_JIS\" />\n"
			+ "<title>セッション・デモ</title>\n"
			+ "</head><body>\n"
			+ "<h1>セッション・デモ</h1>\n"
			+ "<p>" + msg + "</p>\n"
			+ "<p>サーブレットコンテナが割り振ったセッションID:" + id + "</p>\n"
			+ "</body></html>\n");

	}
}

本稿では、以前 CLASSPATH にサーブレット・パッケージのアーカイブをセットしているので、次のようにコンパイルできます:

C:\>cd C:\java\session\WEB-INF\classes

C:\java\session\WEB-INF\classes>javac SessionDemo.java

C:\java\session\WEB-INF\classes>

CLASSPATH を設定していない方は、 -classpath フラッグで、Tomcat のインストール・ディレクトリ内の common\lib\servlet.jar を設定する必要があります。デフォルトでは C:\Program Files\Apache Tomcat 4.0\common\lib\servlet.jar です。

動作確認

このサーブレットは、 server.xml によって、コンテキスト・ルート /session にマップされており、更に、 web.xml によって、 URL パターン /demo にマップされています。マシン・リソースを http://localhost:8080 で識別すると、このサーブレットは http://localhost:8080/session/demo でアクセスできます。

server.xmlweb.xml の更新は、 Tomcat の再起動によって反映します。開始/停止は Tomcat アイコンから実施します。

Tomcatアイコン
図: Tomcat アイコン
Tomcat の開始
図: Tomcat の開始

Tomcat が正常に開始したら、ブラウザで次の URL を要求します。

http://localhost:8080/session/demo
最初の要求
図:最初の要求
二回目以降の要求
図:二回目以降の要求

セッション管理

Cookie

HttpSession によって、セッションがどのように管理されているか確認します。

最初のアクセス時に HttpSession オブジェクトが作成され、セッション ID が割り振られます。クライアントには、 HTTP ヘッダに埋め込まれる形で cookie が送付されて ID が保持されます。二回目以降のアクセス時には、クライアントから送られた cookie に記述されたセッション ID から、特定の HttpSession オブジェクトが識別されて、前回の要求/応答に継続した処理が可能になります。

一般に、 Cookie には文字列だけが保持され、サーバにアクセスする度に、保持している全ての Cookie が送信されます。HttpSession では、作成する Cookie にはセッション ID だけを格納します。無関係のサーバに送信された Cookie が不正に取得されても、記述されているのは ID だけなので無価値となり、クライアントにとっては安心です。

一方、セッション ID で識別される HttpSession には任意のオブジェクトが Object 型で保持することが可能です。キーワードを指定してオブジェクトを格納/取り出しが可能です。

非 Cookie

クライアントによっては、 Cookie を拒否するように設定しています。非明示的にサーバにローカル・ディスク内の情報を送信される事を嫌うためです。事実、 Cookie を利用した不正アクセスは後を絶ちません。

このようなユーザには、上記の HttpSession による処理に加えて、 URL に情報を付加するようにします。これを行うのが、 HttpServletResponse オブジェクトの encodeURL() メソッドです。これを実装しておけば、 Cookie が利用できる場合はなにもせず、利用できない場合だけ引数の URL を加工して、セッション ID を付加した URL を返します。

String nextURL = response.encodeURL("./secondServlet");
out.println("<a href=\"" + nextURL + "\">次のページ</a>");

JSP

JSP では、 HttpSession オブジェクトは、暗黙オブジェクト session として作成されています。ここには、 session スコープのオブジェクトが保持されます。



Copyright © 2002 SUGAI, Manabu. All Rights Reserved.
SEO [PR] 爆速!無料ブログ 無料ホームページ開設 無料ライブ放送