2010-10-31

Cookie の使い方 - GAE におけるセッションの保持

前回(「iPhone アプリらしく #2」)にも書いたように、Blogger Glass は「画面遷移だけの(とても古臭い)ウェブアプリ」だ。これを iPhone アプリらしく見せるためには、ぜひとも「Back」ボタンが必要だ。というのも、iPhone アプリでは、ある画面からボタンやら何やらを押すことで子画面を開き、そこで作業が完了すると親画面に戻る、という操作が良く実装されている。このユーザ体験を実現することは、iPhone アプリとしてごく標準的なことなのだ。

しかし、ウェブアプリでこれ(一つ前に開いていた画面に戻る)をやろうとすると、セッションの保持(と管理)という壁にぶつかる。ステートレスな HTTP 上に作られるウェブアプリの宿命だ。

Blogger Glass では、ここまでセッション管理にまつわることを避けてこれたが、それもそろそろ限界。このあたりで、ちゃんとセッション周りを実装することにしよう。

実現方法

ウェブアプリにおけるセッションの概念とは、たとえるなら病院(医者)とそこに治療に来る患者の間にあるものだ。初診時に治療セッションが始まり、完治によって終了する。

患者は病気なりケガなりの治療で数回、病院を訪れることになる(セッションの継続)。その度に、病院(医者)の側が患者のことをすっかり忘れてしまっては治療は成立しない。病院(医者)は個々の患者について、病気(やケガ)の状態と治療の経過を記録しておかなければならない。それが患者ごとに用意されるカルテと呼ばれる記録だ。

一方、カルテに書かれた記録を有効に利用するためには、患者一人一人を識別できるようにする必要がある。大抵は(カルテに書かれた)患者の名前で間に合うが、中には同姓同名の患者もいるから常に確実な方法とは言えない。そんなわけで患者に一意の番号を割り当て、それでカルテと患者をひもづける。でも、患者にとったら何桁にもなる番号を覚えるのは大変なので、病院はこの番号を記録したカード、すなわち診察券を用意して、初診時に患者にわたす。

病院がウェブアプリで患者がブラウザ、カルテはウェブアプリが記録するセッション情報で、カルテと患者をひもづける番号がセッション ID という対応関係になる。

残るは診察券に対応するモノ(ブラウザ側にセッション ID をわたすための仕組み)だが、これには 3 つの方法がある。すなわち、(1) URL に埋め込む方式、(2) HTML のフォームに隠し要素として埋め込む方式、(3) cookie を使ってわたす方式、の 3 つだ。

練習も兼ねて、今回は (3) の方式でセッションを実現してみる。

サンプルプログラム

以下のサンプルプログラムでは、セッション情報(整数値 1 つ)は GAE の提供するストレージサービスの 1 つである memcache を利用している。このサービスはもう 1 つのデータストアとは違い、「揮発性」のストレージだ。容量も(データストアに比べればかなり)小さい。その代わり、ずっと高速に動作するらしい。頻繁にアクセスする少量のデータは、memcache に置く方が良い。

このプログラムを GAE アプリのリクエストハンドラにしてアクセスすると、「Back」と「Forward」という 2 つのリンクを持つページが開く。Forward をたどると memcache 中のデータ(カウンタ)がインクリメントされ、Back をたどればデクリメントされる。ただ、それだけのプログラムだが、内部的にはセッション管理がなされており、memcache に保持される値はクライアントごとに用意される。実際に複数のブラウザで開けばそのことがわかる。

memcache に保存するカウンタとは別に、データストアにも 1 つ値を保存している。これはセッション管理そのものとは関係ない。この値は、セッションを作るために必須の ID (先の病院と患者のたとえで言うなら、カルテと患者をひもづける番号だ) を作るための「種」になっている。

セッション管理の仕組み自体は単純で、リクエストを受けたら(ハンドラの get メソッドが呼ばれたら)、ブラウザが送ってきた cookie からセッション ID を取り出す。次にセッション ID をキーとして memcache からカウンタの値を取り出す。

ブラウザが cookie を送ってこなかった、あるいは(このプログラム用の)セッション ID がふくまれていないときは、新しくセッション ID を生成しレスポンスヘッダに入れる。

「Back」ボタンを実装するには

Blogger Glass (の iPhone 用画面)に「Back」ボタンを実装するには、画面を開くときにリクエスト URL をセッション情報として保存すれば良い。「Back」ボタンには専用のリクエスト URL を用意しておく(たとえば /back)。そのリクエストハンドラでは、セッション情報から保存されたリクエスト URL を取り出し、そこにリダイレクトする。

まだ、コードを書いていないから確信はないけれど、だいたいこんな感じで動きそうだ。

関連リンク

関連記事

0 件のコメント:

コメントを投稿