shoota works

Apache-Tomcatのプロキシ設定を変更したらsessionがとれなくなった

Apache-Tomcatのプロキシ設定を変更したらsessionがとれなくなった
Photo by

Java アプリで session スコープに保存した POJO を取得できずにハマったときのメモ。

構成

  • アプリのフレームワークは Spring3。通常の Servlet アプリケーション。
  • 前段の Web サーバに Apache、Java アプリのコンテナとして Tomcat を用いて、両者の連携は mod_proxy_ajp を利用。

やりたいこと

ふつうに session スコープに保存した object を別のパスで取得する。
イメージとしては下の感じ。

 
package hoge.foo.contoroller
 
 
import hoge.foo.LoginForm
 
@RequestMapping(value="/user")
public class UserController{
 
    private static final String SESSION_FORM_NAME = "user_input_data"
 
    /**
    * ログイン
    */
    @RequestMapping(value="/login", method=RequestMethod.POST)
    public String login(
        @Valid @ModelAttribute LoginForm form,
        BindingResult result,
        HttpServletRequest request,
        Model model) {
 
      if(result.hasError){
        return "login";      //入力エラー
      }
 
      // ログインに関する処理
 
      request.getSession().setAttribute(SESSION_FORM_NAME, form);  //session格納
      return "dashboard";
    }
 
 
 
    /**
    * セッションのユーザデータを参照して編集画面を表示する
    */
    @RequestMapping(value="/edit", method=RequestMethod.GET)
    public String editView(
        HttpServletRequest request,
        Model model) {
 
      LoginForm form = request.getSession().getAttribute(SESSION_FORM_NAME);
 
      if(form == null) {
        return "login";     // ログイン画面に戻る
      }
      //後続処理
 
      return "edit";
    }
 
}
 

session からデータがとれない!

/user/editを叩いても常に/user/loginに遷移する。つまりform == nullが常に true となってしまっている。
念のためデバッガでステップ実行してみても、やはりformが null である。

セッションタイムアウトの設定や Spring でのセッションの利用方法など、あらゆるドキュメントを確認するも、
まったく解決の糸口が掴めない。なんだ....なにが悪いっていうんだ....!!

あっ!

ここで、前日の開発で別のコンテキストパスで動作させるために、server.xml と httpd.conf のProxyPassを変更したことを思い出す。
httpd.conf はこんな感じ。

ProxyPassMatch  /  ajp://localhost:8009/spring/

そしてJSESSIONIDがクッキーに保存されていて、クッキーには Path があって......!?

あれ...?もしかしてセッション ID のクッキーの Path、ずれてるんじゃない...?

とりあえずリバースプロキシの設定を戻し、Apache と Tomcat を再起動。

ProxyPassMatch  /  ajp://localhost:8009/

##あー、とれたわー。session から普通に object 取得できたわー。

ちなみにリバースプロキシでパス階層がずれる場合は、ProxyPassReverseCookiePathディレクティブを使うらしいです。