nodejs express-sessionのセッションクッキーでajax request時の情報が保持されない


expressのsessionでmaxAge=nullでセッションクッキー用(ブラウザを閉じたら消える)を利用して、情報の保持をしていたら何故かajaxリクエストによりセットしたsession上のデータが他のリクエストに引き継がれないので少しハマりました。以下、簡単なメモ。

session cookieを使うために、おそらく以下のようなコードをapp.jsに記述しているのではないかと思います。

app.use(session({
    secret: 'lunchTimer',
    saveUninitialized: true,
    resave: true,
    cookie: {
        maxAge: null
    }
}));

でデータをsessionに詰めるためには以下のようにセットするだけ。

req.session.hoge = "hogehoge";

少し前にここら辺のsetupに関する記事を書きました。
https://tejitak.com/blog/?p=441

これが不思議なことに、ajax requestで受け付けたroutesの中でセットしたsessionのデータが、他のリクエストが受け付けられたタイミングで消えてる現象が起きました。

理由: resaveをfalseにしないと同時に発行した別のajax requestにsessionデータがを上書きされる

app.jsでsessionを使う設定をしているところのresaveというやつ。何も考えずにtrueでセットしてしまってました。

これ公式のドキュメントを見るとわかるのですが、requestを受け付ける度にsessionのデーターを保存し直しています。今回の私の例ではxhrリクエストをほぼ同時に2発投げていて、片方の処理でsessionに情報を詰めていました。

そして、sessionに対して何も処理をしない後から受け付けたxhr処理により、元のデータがsaveされてしまい直前に行った変更が破棄されていました。

https://github.com/expressjs/session

resave – forces session to be saved even when unmodified. (default: true)

なので、直し方はresave = falseとするのと、明示的に必要な部分でsession.save()を呼ぶ。

app.use(session({
    secret: 'lunchTimer',
    saveUninitialized: true,
    resave: false,
    cookie: {
        maxAge: null
    }
}));

ちなみにresaveをfalseにすると、毎回自動的にsessionデータの変更による保存はされないですが、express-sessionのindex.jsのshouldSave()の実装を見ると、sessionのデータのhash値を見て以前と違いがあったらsaveするというコードがありました。
つまり基本的にはsessionのデータが変更されれば自動的にsaveされますが、ちゃんと変更したタイミングで明示的にsaveを呼んであげた方が無難です(このhashの実装にもよりますが)。

以下のような感じ

req.session.hoge = "hogehoge";
req.session.save(function(){ res.send('{}') });

無事、xhrでセットしたセッションデータが保持されました。めでたし。