Search on the blog

2013年2月9日土曜日

JavaでCookie使うときの注意

 以下のプログラムは、クッキーを使ってカウントアップしていくプログラムです。しかし、問題があります。何がまずいでしょうか?
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class Test extends HttpServlet {
    private static final long serialVersionUID = 1L;

    protected void doGet(HttpServletRequest request,
            HttpServletResponse response) throws ServletException, IOException {
        
        Cookie[] cookies = request.getCookies();
        Cookie cookie = null;
        
        if (cookies != null) {
            for (int i = 0; i < cookies.length; i++) {
                if ("counter".equals(cookies[i].getName())) {
                    cookie = cookies[i];
                    response.getWriter().write(cookie.getValue());
                    break;
                }
            }
        }
        
        if (cookie == null) {
            cookie = new Cookie("counter", "0");
            cookie.setPath("/");
            cookie.setMaxAge(60*60);
        } else {
            int counter = Integer.valueOf(cookie.getValue());
            counter++;
            cookie.setValue(Integer.toString(counter));
        }
        response.addCookie(cookie);
    }

}
実は上のプログラムだと、クッキーが2つできてしまいます。

設定したい名前のクッキーが存在するときは、その値をインクリメントして値を更新して、レスポンスに書く。という処理をしていますが、これだけでは足りません。

int counter = Integer.valueOf(cookie.getValue());
counter++;
cookie.setPath("/");
cookie.setMaxAge(60*60);
cookie.setValue(Integer.toString(counter));
のように最大寿命、パスを再設定してあげないといけません。 最初のソースコードでは、newしたクッキーのパスは"/"、更新するときのクッキーのパスはnullとなっていて、パスが異なるため同じ名前のクッキーが2つ出来てしまいます。
「なんだこの仕様面倒くさいなー。何でパスとか最大寿命とか再設定しないといけないの?サーブレットコンテナの中で管理してよ。」と思いましたが、よくよく考えるとHTTPリクエストのヘッダーにはクッキーの名前、値しか乗らないので、あたり前の仕様ですね。

[Request Headers]
Cookie: counter=5

[Response Headers]
Set-Cookie:counter=6; Expires=Fri, 08-Feb-2013 18:05:16 GMT; Path=/

のようにサーバーからのレスポンスには最大寿命とかパスが乗りますが、UAからのリクエストには乗らないので、getCookiesしたときにこれらの値はとれるはず無いですと。なるほど。

0 件のコメント:

コメントを投稿