#はじめに
Node.js+セッションDBにてWEBページを構築していたのですが、sessionが更新されない事象があったためその対処法のメモです。
セッションはメモリ上ではなくRDB(PostgreSQL)上に持ちます。PostgreSQLに対してはpgpool-IIを使用してのアクセスとなります。
#先に結論
セッションを作成する箇所において
resave : true
resaveをfalseではなくtrueにします。
また、各セッション更新箇所において
req.session.save();
をやめます。
これでセッションが更新されないことは(今のところ)なくなりました。
#環境
- Node.js : v6.10.0
- PostgreSQL : 9.6
- pgpool-II : 3.6.1
- npmパッケージ群
- pg : 6.1.4
- express : 4.14.1
- express-session : 1.15.1
- connect-pg-simple : 3.1.2
#事象説明
##ページ構成
URI | method | 機能 |
---|---|---|
/ | GET | ログインページを表示 |
/login | POST | ユーザIDとパスワードを元にログイン処理を実施 |
/menu | GET | ログインOKの場合メニューを表示。メニューはユーザIDによって見れるものと見れないものがある。 |
ユーザIDとパスワード、およびどのめにゅーを表示させるかの情報(以下、メニュー権限)は全てRDBに保持してます。
POST:/loginでユーザIDとパスワードが一致した場合、メニュー権限をセッションに格納しGET:/menuします。
GET:/menu時にセッションにあるメニュー権限を見て、どのメニューを表示/非表示するかを決めます。
##発生事象
【POST:/loginでユーザIDとパスワードが一致した場合、メニュー権限をセッションに格納するが、その後のGET:/menuにて格納したはずのメニュー権限が取得できない(undefinedになる)】
といった事象が発生しました。
※必ず発生する者ではなく、数回に一回発生する程度。
##原因調査
POST:/loginにて格納されたメニュー権限をコンソールに出力すると正常なのに、GET:/menu時にはundefinedになっていることから
「RDBへの書き込みが間に合っていない?」
のかと思いました。
しかし、RDBのログ等調べても原因はわからず・・・
##その時のセッション関連のソース
// ・・・(省略)・・・
var pg = require('pg');
var session = require('express-session');
var pgSession = require('connect-pg-simple')(session);
app.use(session({
store : new pgSession({
pg : pg,
conString : 'postgres://postgresql:postgresql@127.0.0.1:5432/database',
clear_interval : '300'
}),
secret : 'secret',
resave : false,
saveUninitialized : true,
rolling : true,
cookie : {
httpOnly: false
}
}));
// ・・・(省略)・・・
router.get('/', function(req, res, next) {
// ・・・(省略)・・・
req.session.menuAuthority = '(取得したRDBの情報)';
req.session.save();
// ・・・(省略)・・・
});
上記の箇所以外でもセッションを更新したあとは必ず
req.session.save();
を行うようにしてました。
このせいで先の「RDBへの書き込みが間に合っていない?」が発生してしまっているのでは?と思い、
req.session.save();
をやめる対応を行いました。
##修正後のapp.js
var pg = require('pg');
var session = require('express-session');
var pgSession = require('connect-pg-simple')(session);
app.use(session({
store : new pgSession({
pg : pg,
conString : 'postgres://postgresql:postgresql@127.0.0.1:5432/database',
clear_interval : '300'
}),
secret : 'secret',
resave : true, // falseからtrueへ
saveUninitialized : true,
rolling : true,
cookie : {
httpOnly: false
}
}));
上記の変更、および各処理において
req.session.save();
をやめたことによりGET:/menuでもメニュー権限をセッションから取得できるようになりました。
#その他
「RDBではなくメモリ上で管理したらどうなったか?」
については試してません。(メモリ上なら問題になっていないのではないかと思いますが。。。)