同じ名前のクッキーを二つ返した際の挙動
同じ名前のクッキーをブラウザに返すと、後にセットしたクッキーが使われるんだよなぁ・・と思い、試してみた。MyFaseを使ったアプリがあったので、PhaseListenerのbeforePhaseとafterPhaseを利用。コードは下記の通り
package test;
import javax.faces.context.ExternalContext;
import javax.faces.event.PhaseEvent;
import javax.faces.event.PhaseId;
import javax.faces.event.PhaseListener;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class TestPhaseListener implements PhaseListener {
/**
* クッキーの名前。今回は同一名で二つ作成するため、この名前を使いまわす
*/
private final String COOKIE_NAME = "test_Cookie";
/**
* クッキーの値1
*/
private final String COOKIE_VALUE_1 = "cookie_Value_No1";
/**
* クッキーの値2
*/
private final String COOKIE_VALUE_2 = "cookie_Value_No2";
/**
* ブラウザの有効期間
* ブラウザを閉じるまで有効なクッキー
*/
private final int COOKIE_MAXAGE_SESSION = -1;
/**
* ブラウザの有効期間
* 即削除される
*/
private final int COOKIE_MAXAGE_DELETE = 0;
public void beforePhase(PhaseEvent event) {
// クッキーをセット。値1を指定
createAndSetCookie(event, COOKIE_NAME, COOKIE_VALUE_1, COOKIE_MAXAGE_SESSION);
}
public void afterPhase(PhaseEvent event) {
// クッキーをセット。値2を指定
createAndSetCookie(event, COOKIE_NAME, COOKIE_VALUE_2, COOKIE_MAXAGE_SESSION);
}
private void createAndSetCookie
(PhaseEvent event, String cookieName, String cookieValue, int cookieMaxAge)
{
// ExternalContextを取得
ExternalContext context = event.getFacesContext().getExternalContext();
// リクエストとレスポンスを取得
HttpServletRequest request = (HttpServletRequest)context.getRequest();
HttpServletResponse response = (HttpServletResponse)context.getResponse();
// 受け取った名前と値を持つクッキーを作成する
Cookie cookie = new Cookie(cookieName, cookieValue);
// クッキーの有効期間を設定
cookie.setMaxAge(cookieMaxAge);
// 有効なパスを設定する。同一ホスト上、全てに対して有効
cookie.setPath(request.getContextPath());
// レスポンスにクッキーをセット
response.addCookie(cookie);
}public PhaseId getPhaseId() {
// TODO Auto-generated method stub
return PhaseId.RESTORE_VIEW;
}
}
JSFを知らない人向けの解説。
とあるフェーズの開始前と終了後に同じ名前のクッキーをセットしている。名前の通り「beforePhase」が開始前、「afterPhase」が終了後。開始前に値1を、終了後に値2をセットする。
結果:レスポンス
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Set-Cookie: test_Cookie=cookie_Value_No1;
Set-Cookie: test_Cookie=cookie_Value_No2;
:
結果:上記レスポンスを受け取った後のリクエスト
値2が残ってるね。まぁ当たり前か。ちなみに逆にしてみたら値1が残ったので、後からセットされたほうが優先らしい。
次、後からセットしたクッキーのMaxAgeが0だった場合。クッキーのMaxAgeが0だとブラウザがクッキーを削除するのだけど、最初にセットされたクッキーまで削除されるのか?
コードを少々修正。
:
/**
* ブラウザの有効期間
* ブラウザを閉じるまで有効なクッキー
*/
private final int COOKIE_MAXAGE_SESSION = -1;
/**
* ブラウザの有効期間
* 即削除される
*/
private final int COOKIE_MAXAGE_DELETE = 0;
public void beforePhase(PhaseEvent event) {
createAndSetCookie(event, COOKIE_NAME, COOKIE_VALUE_1, COOKIE_MAXAGE_SESSION);
}
public void afterPhase(PhaseEvent event) {
createAndSetCookie(event, COOKIE_NAME, COOKIE_VALUE_2, COOKIE_MAXAGE_DELETE);
}
:
結果:レスポンス
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Set-Cookie: test_Cookie=cookie_Value_No1;
Set-Cookie: test_Cookie=cookie_Value_No2;
:
結果:上記レスポンスを受け取った後のリクエスト
:
Cookie: JSESSIONID=***;
:
あら、最初にセットしたもの一緒に消えてるね。ちなみに逆にすると、
:
public void beforePhase(PhaseEvent event) {
createAndSetCookie(event, COOKIE_NAME, COOKIE_VALUE_1, COOKIE_MAXAGE_DELETE);
}
public void afterPhase(PhaseEvent event) {
createAndSetCookie(event, COOKIE_NAME, COOKIE_VALUE_2, COOKIE_MAXAGE_SESSION);
}
:
結果:レスポンス
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Set-Cookie: test_Cookie=cookie_Value_No1;
Set-Cookie: test_Cookie=cookie_Value_No2;
:
結果:上記レスポンスを受け取った後のリクエスト
後からセットしたクッキーが残っていることを確認。
結論。
・同じ名前のクッキーは後からセットしたものが有効で、先にセットされたものは破棄される。
・有効なクッキーと削除するクッキーを同じ名前で一緒に送った場合、後からセットしたのが有効ならそれが残る。後からセットしたものが削除するクッキーだった場合は両方削除される。
つまり、レスポンスを見ると同じ名前のクッキーが二つ返されれているけれども、最初にセットしたクッキーは無効ということ。
まぁ当たり前だけど、ちゃんと確認できた。
もしかしたらRFCあたりを解読すれば書いているかもしれない。ブラウザに依存しそうだから、あまりやらない方がいいのかもしれないね。