HTTPはステートレスなプロトコルなので、画面遷移間で一連の処理であることを識別する仕様はHTTPには無い。
が、それでは不便な場面が多々あるので、セッションという仕組みが考案された。
一連の処理の開始時(例えばログイン時)に、サーバー側でセッションIDを割り振り、クライアントへ渡す。
(“セッションIDに付随する情報”は、サーバー側で保持する)
クライアントがサーバーへ要求を送るときには、割り振られたセッションIDも一緒に送る。
これにより、サーバー側では同一セッションであることを認識できる。
(サーバー側で保持した“セッションIDに付随する情報”が継続して使える)
サーバー側としては、異なるセッションIDが来たら、別セッションと認識する。
クライアント(ユーザー) | サーバー | |
---|---|---|
ログイン画面を開く。 | → | ログイン画面を返す。 |
ログインする。 (パスワード等を入力) |
← | |
→ | セッションIDを発行。 次の画面を返すときにHTTPレスポンスにセッションIDを含める |
|
ボタンを押したりして次の画面を開く。 HTTPリクエストに、渡されたセッションIDを含める |
← | |
→ | セッションIDを見てセッションを識別する。 次の画面を返すときにHTTPレスポンスにセッションIDを含める |
|
ボタンを押したりして次の画面を開く。 HTTPリクエストに、渡されたセッションIDを含める |
← | |
→ |
セッションIDをサーバーからクライアントへ渡す方法は、いくつか考えられる。
方法 | サーバー → クライアント | クライアント(ブラウザー) → サーバー |
---|---|---|
URL rewriting URLリライティング |
HTML内のリンクのURLにセッションIDを埋め込む。 例: <a href="go.html;sessionID=hoge">〜</a> |
リンクをクリックすることで、セッションIDがURLと一緒に書かれているので、サーバーにそのまま送られる。 |
cookie クッキー |
クッキーにセッションIDを保持する。 | HTTPリクエスト(のクッキー)の中に、ブラウザーが自動的にセッションIDを含めてくれる。 |
hidden | HTMLのFORMのhidden項目にセッションIDを入れる。 例: <input type="hidden" name="sessionID"
value="hoge"> |
サブミットすることで、hidden項目のセッションIDがHTTPリクエストの中に含まれる。 |
URLリライティングだと、HTML内のセッションに関係するURL全てにセッションIDを書かなければいけなくなるし、ユーザーから見えるURL部分にセッションIDが現れてくるのでちょっと嫌。
クッキーを扱わないブラウザー(あるいはクッキーを受け入れないユーザー)も存在するので、クッキーのみに頼ることは出来ない。
hiddenはサブミットしたときにしかサーバーに情報が渡らないので、リンクによる画面遷移には不向き。
という訳で、APサーバーがセッション管理機能を持っている場合は、URLリライティングとクッキーの併用が多いようだ。
つまり、初回は(ブラウザーがクッキーを受け入れるかどうか分からない為)、URLリライティングとクッキーを両方ともセットしてクライアントへ送る。
次のクライアントからの要求時に、クッキーが入っていれば(クッキーが使えるブラウザーだと認識し)今後はクッキーのみ使用する。
クッキーが入っていなければ(クッキーを扱わないブラウザーだと認識し)今後はURLリライティングのみ使用する。
ちなみに携帯電話のブラウザーではクッキーは使えないので、必然的にURLリライティングのみになる。
セッションIDはサーバーとクライアント間でやりとりするが、一連の処理中に使いたい情報自体はサーバー側で保持する。
普通は当然サーバーのメモリ上に持っているだろうが、Webサービスでは、複数サーバーで構築するのも当たり前。
つまり、セッション中(一連の処理を行っている最中)のリクエストは、それを処理しているサーバーに常に来てくれなければならない。
(同一セッションIDなら同一サーバーでないと、セッション情報を持っていない)
ロードバランサー(負荷分散装置)を用意して、セッションパーシステンスを使う(同一セッションであれば同一サーバーへ振り分ける)のが一般的かと思う。
この制限をクリアする為には、セッション情報を個々のサーバーのメモリ上ではなく、共有できる場所に置けばよい。(セッションレプリケーション(セッション情報の複製))
つまり、共有ファイルや共通のDBにセッション情報を格納するということ。あるいはTCP等によるサーバー間通信でセッション情報をやりとりする実装もあるようだ。
ただし、当然、共有ファイルアクセスやDBアクセス、あるいは通信に伴うコストが発生する。
セッション情報を共有しておけば、サーバーがダウンした場合にも他サーバーでセッションを継続することも出来る。
共有方法は、例えばAPサーバーが6台あったとして、6台全てで共有する方法も考えられるし、2台ずつペアにしてお互いのバックアップとする(その2台の間でだけ共有する)といった方法が考えられる。
セッション情報を複製するタイミングは、レスポンスをクライアントへ返す直前というのがたぶん一番現実的だと思う(Tomcat5.5ではそうしているのだそうだ)。