URL書き換え

広告

今までのサンプルではクライアント側のブラウザでクッキーを受け入れる設定になっていることが前提となっていました。セッションは開始された後、セッションIDをクライアント側にクッキーとして保存することで、クライアントを識別しどのセッションがどのクライアントのためのものなのかを識別しているためです。

ただ、不特定多数のクライアントから利用されるサーブレットの場合、全てのクライアントがクッキーを受け入れる設定になっているわけではありません。クッキーが使えないクライアントからでもセッションを利用できるようにするためにはURLをセッションID付きのものに書き換える必要があります。

クッキーが使える場合に、クライアントからはサーブレットへのリクエストと同時に自分が持っているクッキーをサーバに送ってきます。その仕組みの変わりに、サーブレットへのリクエストそのものにセッションIDを含めてしまうということになります。これはURLを次のように書き換えることで対応できます。

通常のサーブレットへのリンク:

http://localhost:8080/session/sessiontest

セッションID付サーブレットへのリンク:

http://localhost:8080/session/sessiontest;jsessionid=(セッションID)

このようにセッションID付きのURLをクリックするなどしてサーバへリクエストを送ると、サーバ側ではそこからセッションIDを抜き出してクッキーがある場合と同じような処理をしてくれます。

ここでURLに付加するセッションIDは、クライアント毎にそしてセッション毎に異なるため、固定して記述することは出来ません。まずクライアントが最初にサーバへアクセスした時にセッションを開始し、そこからセッションIDを取得した上で、それ以降クリックされる全てのURLにセッションIDを付与した形でHTMLをサーブレットが出力する必要があります。

このセッションID付きのURLの生成ですが、「HttpServletResponse」インターフェースで定義されている"encodeURL"メソッドを使うことで自動的に行うことができます。

Encodes the specified URL by including the session ID in it, or, if 
encoding is not needed, returns the URL unchanged. The implementation
of this method includes the logic to determine whether the session ID
needs to be encoded in the URL. For example, if the browser supports 
cookies, or session tracking is turned off, URL encoding is unnecessary. 

For robust session tracking, all URLs emitted by a servlet should be 
run through this method. Otherwise, URL rewriting cannot be used with 
browsers which do not support cookies. 

Parameters:
  url - the url to be encoded. 
Returns:
  the encoded URL if encoding is needed; the unchanged URL otherwise.

このメソッドは引数にURLを表す文字列を指定して実行すると、セッションID付きのURLに変換して出力してくれます。サーブレットを通じて出力されるリンクは全てこのメソッドを通した結果得られるURLを使う必要があります。

例として、下記のような記述を行っていたサーブレットを考えてみます。

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

  response.setContentType("text/html; charset=Shift_JIS");
  PrintWriter out = response.getWriter();

  HttpSession session = request.getSession(true);

  out.println("<a href=\"/session/sessiontest\">再表示</a>");
}

URL書き換えを行う場合には次のように記述します。

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

  response.setContentType("text/html; charset=Shift_JIS");
  PrintWriter out = response.getWriter();

  HttpSession session = request.getSession(true);

  String eURL = response.encodeURL("/session/sessiontest");
  out.println("<a href=\"" + eURL + "\">再表示</a>");
}

またこのメソッドは、必要無ければ書き換えを行いません。つまりクッキーが使える状態で、クッキーからセッションIDを取得出来る場合にはこのメソッドを使ってもセッションIDの付与は行われません。少し分かりにくいのでこの後のサンプルで確認して下さい。

サンプルプログラム

では試してみます。

web.xmlファイルは下記のようにしました。

<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
   http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
  version="2.4">

  <servlet>
    <servlet-name>sessiontest</servlet-name>
    <servlet-class>SessionTest8</servlet-class>
  </servlet>

  <servlet-mapping>
    <servlet-name>sessiontest</servlet-name>
    <url-pattern>/sessiontest</url-pattern>
  </servlet-mapping>
</web-app>

プログラムは下記の通りです。

SessionTest8.java

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

public class SessionTest8 extends HttpServlet {
  public void doGet(HttpServletRequest request, HttpServletResponse response)
    throws IOException, ServletException{

    response.setContentType("text/html; charset=Shift_JIS");
    PrintWriter out = response.getWriter();

    HttpSession session = request.getSession(false);

    out.println("<html>");
    out.println("<head>");
    out.println("<title>セッションテスト</title>");
    out.println("</head>");
    out.println("<body>");

    if (session == null){
      out.println("<p>セッションを開始します</p>");
      session = request.getSession(true);
    }else{
      out.println("<p>セッション中です</p>");
    }

    String session_id = session.getId();

    out.println("<p>");
    out.println("セッションIDは" + session_id + "です<br>");
    out.println("</p>");

    String url = "/session/sessiontest";
    String eURL = response.encodeURL(url);

    out.println("<p>");
    out.println("書き換え前: " + url + "<br>");
    out.println("書き換え後: " + eURL);
    out.println("</p>");

    out.println("<a href=\"" + eURL + "\">再表示</a>");

    out.println("</body>");
    out.println("</html>");
  }
}

上記をコンパイル後に「d:\servlet-sample\session\WEB-INF\classes\」ディレクトリにクラスファイルを移動した後で、ブラウザで「http://localhost:8080/session/sessiontest」へアクセスしてみます。クッキーは無効にしておいて下さい。

URL書き換えによるセッション利用

URLがどのように書き換えられるのかを表示しています。また「再表示」の箇所にはセッションIDを付与されたURLがリンクされています(画面下部で確認して下さい)。では「再表示」をクリックして下さい。

URL書き換えによるセッション利用

クッキーが使えない状態でもセッションは維持されています。

次にブラウザの設定でクッキーを有効にした状態で同じテストをしてみます。

URL書き換えによるセッション利用

クッキーが有効な状態でもセッション開始時の場合はURL書き換えは行われます。では「再表示」をクリックして下さい。

URL書き換えによるセッション利用

セッションが維持されるのは同じですが、今度はURL書き換えが行われません。正確には分からないのですが、クッキーが使える状態の場合はクッキーからセッションIDが取得できたため、URL書き換えによるURLへのセッションID付与が行われませんでした。

※今回のテストではブラウザをFireFoxにしていますが、Internet Explorerでクッキーの無効化がうまく出来なかったためです。

URL書き換えはクッキーが使えないクライアントでもセッションを利用できるようになり便利なのですが、URL自体にセッションIDを記述してしまうとセッションIDがそのままログなどにも残ってしまいセキュリティ上問題があります。その為、この方法は推奨はされておらずあくまでクッキー利用を前提にしたほうがいいかと思います。

( Written by Tatsuo Ikura )

プロフィール画像

著者 / TATSUO IKURA

これから IT 関連の知識を学ばれる方を対象に、色々な言語でのプログラミング方法や関連する技術、開発環境構築などに関する解説サイトを運営しています。