Servlet 3.1より入ったという、HttpServletRequest#changeSessionId、これを使うと現在のHttpSessionのIDを変更できるそうな。
あまり使っているサンプルを見たことがなかったので、自分で試してみました。
使用したアプリケーションサーバは、WildFly 8.1.0.Finalとなります。
こんなServletを作成。
src/main/java/org/littlewings/javaee7/servlet/SessionCountingServlet.java
package org.littlewings.javaee7.servlet; import java.io.IOException; import java.io.PrintWriter; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; @WebServlet("/counting") public class SessionCountingServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse res) throws IOException, ServletException { res.setCharacterEncoding("UTF-8"); HttpSession session = req.getSession(); String firstSessionId = session.getId(); Integer counter = (Integer)session.getAttribute("counter"); if (counter == null) { counter = 0; } else { counter++; } session.setAttribute("counter", counter); Cookie sessionCookie = null; String sessionCookieName = getServletContext().getSessionCookieConfig().getName(); for (Cookie c : req.getCookies()) { if (sessionCookieName.equals(c.getName())) { sessionCookie = c; } } // HttpSessionが存在しない場合に呼び出すと、IllegalStateExceptionがスローされる // Undertowの場合、java.lang.IllegalStateException: UT010033: No session String changedSessionId = req.changeSessionId(); PrintWriter writer = res.getWriter(); String sep = System.lineSeparator(); String requestedSessionId; if (sessionCookie == null) { requestedSessionId = "<None>"; } else { requestedSessionId = sessionCookie.getValue(); } writer.write("<!DOCTYPE html>" + sep); writer.write("<html>" + sep); writer.write("<head>" + sep); writer.write(" <meta charset=\"UTF-8\">" + sep); writer.write(" <title>サンプル</title>" + sep); writer.write("</head>" + sep); writer.write("<body>" + sep); writer.write(" <h1>HttpServletRequest#changeSessionIdのサンプル</h1>" + sep); writer.write(" <div>" + sep); writer.write(" <h2>Counter = " + counter + "</h2>" + sep); writer.write(" <p>RequestedSessionId = " + requestedSessionId + "</p>" + sep); writer.write(" <p>FirstSessionId = " + firstSessionId + "</p>" + sep); writer.write(" <p>changedSessionId = " + changedSessionId + "</p>" + sep); writer.write(" <p>currentSessionId = " + session.getId() + "</p>" + sep); writer.write(" </div>" + sep); writer.write("</body>" + sep); writer.write("</html>" + sep); } }
使い方は簡単、HttpServletRequest#changeSessionIdを呼び出すと、HttpSessionのIDを変更すると共に、新しいSession IDが返却されます。
String changedSessionId = req.changeSessionId();
なお、それ以降に呼び出すHttpSession#getIdも、HttpServletRequest#changeSessionIdの戻り値と同じ値を戻すようになります。
session.getId();
なお、HttpServletRequest#changeSessionIdを呼び出した際にまだHttpSessionが存在しない状態だと、IllegalStateExceptionがスローされます。
// HttpSessionが存在しない場合に呼び出すと、IllegalStateExceptionがスローされる // Undertowの場合、java.lang.IllegalStateException: UT010033: No session String changedSessionId = req.changeSessionId();
今回のサンプルでは、SessionのIDを変更してもSessionに登録した値が参照できることを確認しつつ、リクエストされたCookieに乗ってくる値と変更前のSession IDの値、HttpServletRequest#changeSessionIdの戻り値とHttpServletRequest#changeSessionId呼び出し後のHttpSession#getIdの呼び出し結果を並べてみました。
writer.write(" <h2>Counter = " + counter + "</h2>" + sep); writer.write(" <p>RequestedSessionId = " + requestedSessionId + "</p>" + sep); writer.write(" <p>FirstSessionId = " + firstSessionId + "</p>" + sep); writer.write(" <p>changedSessionId = " + changedSessionId + "</p>" + sep); writer.write(" <p>currentSessionId = " + session.getId() + "</p>" + sep);
では、WildFlyにデプロイして動作確認。
初回アクセス。以下は、Firefoxで取ったキャプチャです。
なんか、初回なのにCookieが来たことになってる…。
とりあえず、Session IDが変更できること、Session IDを変更してもあらかじめsetAttributeした値は継続されることを確認できました。
が、HttpServletRequest#getCookiesで、リクエストされていないSession用のCookieが取得できたのが気になりますね…。そういうもんでしたっけ?
ちょっと確認。こういうデバッグコード仕込んで
System.out.println("=========================================="); System.out.println("session new? = " + session.isNew()); System.out.println("Session Cookie Name = " + sessionCookieName); java.util.Enumeration<String> headerNames = req.getHeaderNames(); while (headerNames.hasMoreElements()) { String header = headerNames.nextElement(); System.out.println("Header: " + header + " = " + req.getHeader(header)); } for (Cookie c : req.getCookies()) { System.out.println(c); if (sessionCookieName.equals(c.getName())) { sessionCookie = c; } } System.out.println("==========================================");
デプロイしてCookie消してアクセス。
初回。
18:36:20,995 INFO [stdout] (default task-13) ========================================== 18:36:21,010 INFO [stdout] (default task-13) session new? = true 18:36:21,010 INFO [stdout] (default task-13) Session Cookie Name = JSESSIONID 18:36:21,011 INFO [stdout] (default task-13) Header: Accept = text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 18:36:21,012 INFO [stdout] (default task-13) Header: Cache-Control = max-age=0 18:36:21,023 INFO [stdout] (default task-13) Header: Connection = keep-alive 18:36:21,024 INFO [stdout] (default task-13) Header: User-Agent = Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:32.0) Gecko/20100101 Firefox/32.0 18:36:21,024 INFO [stdout] (default task-13) Header: Host = localhost:8080 18:36:21,024 INFO [stdout] (default task-13) Header: Accept-Language = ja,en-us;q=0.7,en;q=0.3 18:36:21,025 INFO [stdout] (default task-13) Header: Accept-Encoding = gzip, deflate 18:36:21,025 INFO [stdout] (default task-13) Cookie: JSESSIONID = THOeQGeYV1r3ltwT7kdO54zz.localhost 18:36:21,026 INFO [stdout] (default task-13) ==========================================
やっぱりCookieヘッダないですよね。
2回目。
18:37:01,786 INFO [stdout] (default task-14) ========================================== 18:37:01,789 INFO [stdout] (default task-14) session new? = false 18:37:01,789 INFO [stdout] (default task-14) Session Cookie Name = JSESSIONID 18:37:01,790 INFO [stdout] (default task-14) Header: Cookie = JSESSIONID=5TvyeEkjegTF8XWsS2eYlGYg.localhost 18:37:01,790 INFO [stdout] (default task-14) Header: Accept = text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 18:37:01,790 INFO [stdout] (default task-14) Header: Cache-Control = max-age=0 18:37:01,790 INFO [stdout] (default task-14) Header: Connection = keep-alive 18:37:01,790 INFO [stdout] (default task-14) Header: User-Agent = Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:32.0) Gecko/20100101 Firefox/32.0 18:37:01,790 INFO [stdout] (default task-14) Header: Host = localhost:8080 18:37:01,790 INFO [stdout] (default task-14) Header: Accept-Language = ja,en-us;q=0.7,en;q=0.3 18:37:01,790 INFO [stdout] (default task-14) Header: Accept-Encoding = gzip, deflate 18:37:01,791 INFO [stdout] (default task-14) Cookie: JSESSIONID = 5TvyeEkjegTF8XWsS2eYlGYg.localhost 18:37:01,791 INFO [stdout] (default task-14) ==========================================
ここで初めて、Cookieヘッダが現れますね。
18:37:01,790 INFO [stdout] (default task-14) Header: Cookie = JSESSIONID=5TvyeEkjegTF8XWsS2eYlGYg.localhost
ということは、やっぱり送信されていないCookieが取れていることに…。