一般的には、タイムアウトするまでセッションを維持し、何らかの要求があったら、タイムアウトのためのタイマーをリセットする、といった方法を使います。サーバー側の都合ではタイムアウトまでの時間は短くしたい一方、ユーザー側の都合では「十分に」長くしたい。
Web ベースアプリの場合、ユーザーはブラウザを使ってアクセスするわけですから、ログアウトせずにタブ、ブラウザを閉じたり、他のサイトへ移動したりできます。問題なのは、そのような操作が行われた事をサーバーが知る方法がない事です。結果、決して使われない「ゴミ・セッション」がタイムアウトまで残ってしまいます。これ、何とかしたい。
ブラウザから一定時間間隔で「使っています」シグナルをサーバーに送信し、それを受け取ったサーバーは「このセッションは維持すべき」と判断すればいいのです。一定時間以上「使っています」シグナルが受信できなかった場合、このセッションは不要と判断できます。
このような方法を「ハートビート heartbeat」とか「キープアライブ keepalive」などと言います。
1分ごとに「使っています」をサーバーに送信するとすれば、サーバー側のタイムアウトは1分強まで短くできます。ネットワークの遅延とか、ブラウザ側の負荷とかを考えても数分まで短縮できるでしょう。もっとも、ハートビートの間隔をあまり短くすると、サーバーはその処理に忙殺されてしまうので、あまり短くはできません。
さて、どのように実装するか。必要条件は、ページ本体は更新しないことです。
html に <iframe> というのがあります。ブラウザの画面内の画像が一定時間ごとに更新されるなどに使われているのが iframe です。本体ページは更新されず、iframe 内だけが更新されます。
setInterval() を用いて一定時間ごとに iframe を再ロードすればOKです。iframe 内の表示を更新するならば、「次の画像を下さい」とか要求するのですが、ここでは keepalive のためのサーブレットなどを呼び出します。
・タイマーの起動は <body onLoad> で実行するメソッドで行います。
<body onload="startTimer()">
function startTimer(){
setInterval(keepAlive, TIME); // TIME は heartbeat 送信間隔
}
・iframe 用の <form> を用意します。
<form name="xxx"> ... </form> // これはメインの form
<form name="KeepAlive" target="HeartBeatFrame">
// これがハートビート用の form。target に iframe の名前を指定します。
<input type="hidden" name="HeartBeatInfo" value=....>
// サーバーにパラメータを渡すならば、こんな感じ。セキュリティーのために暗号化しましょう
</form>
・iframe を用意します。
<iframe name="HeartBeatFrame" height="0" width="0">
// 表示する必要はないので、高さ、幅は0にします。表示してもいいけど・・・
・ハートビート送出
function keepAlive(){
document.KeepAlive.action="KeepAlive..."; // KeepAlive を行うサーブレットなどの URI
document.KeepAlive.submit(); // form KeepAlive の target に iframe の名前がセットされているので、iframe だけが更新されます。
}
これだけだと永遠ハートビートが送出されるので、最大○回までとかの制限が必要でしょう。
まだ試していないけど、最大回数近くになったら「まもなくタイムアウトします」などと表示する事もできそうですね。もっとも、ユーザーが放置しているからタイムアウト間近になったわけで、表示しても誰も見ていない可能性が高そうですが・・