皆さん,こんにちは。筆者は先日,アメリカはシリコンバレーに出張に行ってきまして,行きの飛行機の中で映画,ダイハード4.0を観ました。この映画,「4.0」という邦題もなかなかいい感じ(原題は「Live Free or Die Hard」)なのですが,題材はサイバーテロで,「ハッカー」がたくさん出てきます。Nokiaのスマートフォンを使ったり,新しさは随所にあるものの,どこかに侵入に成功するとでっかく「Access Granted」という緑色の文字が出てきたりして,この連載の第15回で取り上げたような,映画における古風なハッカーの表現手法がきちんと守られていてよかったです。

 とは言っても,映画自体はテンポのいいアクションと,何人もの悪者が登場して,それぞれの悪者に対するムカツキ度が最大値に達したころにやっつけられるタイミングの良さで,かなりおもしろかったです。古風なハッカーの表現方法が知りたい方にはぜひおすすめです。それから,筆者はジョン・マクレーン刑事の吹き替えはやっぱり野沢那智が一番だと思います。

 閑話休題。先日,はてなブックマークの注目エントリに以下の記事があがっていました。

PRGパターンって不必要...

 「PRGパターン」という言葉を知らなかった筆者は,それを「RPG」と見間違え,ゲーム関係かと思ってしまったのですが,アクセスしてみると「RPG」ではなく「PRG」で,ウェブサイトの使い勝手に関する,ゲームとは全く無関係の内容であることがわかりました。

 PRGとは「Post/Redirect/Get」の略で,HTTPのPOSTメソッドを使ってデータをサーバーに送信した際に,そのままHTMLを返してその結果を表示するのではなく,その代わりにリダイレクトによって別のURLを表示させることを指しています(図1)。リダイレクトが行われると,その後はGETメソッドでのアクセスになるので,PRGパターンと呼ぶわけですね。

図1:PRGパターン

 PRGパターンという名前は筆者は初めて知りました。確かにPOSTによってデータを受け取った後,別のページにリダイレクトする,という方法自体は結構よく使っているように思います。

 上記で紹介した記事は,その使い勝手についての話題を取り上げており,そこで言及されているのは,以下のページです。

Post/Redirect/Get pattern for web applications

 このページは2003年に書かれたものですから結構古いのですが,この手法自体は現在でも通じるものですし,使いやすさ向上のためによく使っています。

 そこで今回は,このことを発端に,フォームの送信や,「戻る」ボタンや「更新」ボタンと使い勝手などについて考えてみることにしました。

なぜリダイレクトをするのか

 POSTメソッドによって情報を受け取った後,わざわざリダイレクトをする理由は,いくつもありますが,最もよく言われているのは,フォームの内容を複数回送ってしまうことを防ぐことです。

 POSTメソッドの結果として直接ページ情報を返していた場合,ブラウザの再読込機能(「再読込」ボタンを押すなど)を利用してページの内容を更新しようとすると,もう一度同じ内容がサーバーに送られてしまいます。その結果,発注が重複して発生してしまったり,掲示板に二重書き込みが行われてしまったりという危険性があります。リダイレクトをしておけば,再読込されるのは,リダイレクト後のGETリクエストだけですから,その心配はなくなります。

 ただし,その場合であっても,「戻る」ボタンで前のページに戻って(HTTPのリダイレクトの機構を利用している場合は,「戻る」ボタンを押すと,リダイレクト前のPOSTリクエストに戻るのではなく,さらにその前の,フォームが存在するページにまで戻ります),再度データを送信することは簡単にできてしまいます。したがって,リダイレクトを行うことがそのまま,再送信の完全な防止策になるわけではありません。

 もちろん,例えば掲示板の書き込みなどで,再読み込みでは,書き込んだデータを送ってほしくないけれど,「戻る」で戻った場合には,再度送信しても(つまりもう一度書き込みを行っても)構わない,という場合ならこれで事足ります。

 しかし,商品の購入など,絶対に一度しか処理を行いたくない場合には,例えば送信元のページでワンタイムトークン(その場でランダムに生成したユニークなコードなど)を生成して,一つのトークンに対しては1度しか処理を行わないようにしたり,もしくは登録作業全体を一つのセッションとしてセッションIDを振り,セッションIDが同じであれば,何度処理をしても同じセッションのものだと判断して作業を行う,といったことで対応できます。

 フォームの場合は,ワンタイムトークンやセッションIDをhiddenで非表示にしたINPUT要素の格納して,POSTの際に同時に送信することで,サーバーにその値を認識させるわけですね(図2)。

図2:セッションIDを使って多重登録を回避する

 逆に,この手法を使っていれば,PRGパターンって本質的には必要ではありません。情報の再送信で発生する問題は解決されているからです。

 しかし,それでもリダイレクトをすることには意味があります。なぜかというと,POSTメソッドによってアクセスされたページを再読込すると,ブラウザは「もう一度情報をPOSTしちゃうけどいい?」という以下のようなダイアログを表示してしまうからです(図3)。

図3:ブラウザが表示するデータ再送信の警告

 これはもちろん,ブラウザが親切で出してくれるものです。しかし,ページの再読み込みが行われやすいタイプのページでは,たとえ多重登録の危険性が無くても,こうしたメッセージが出てしまうこと自体,利用者にとっては「再試行」してもいいものなのかどうかわからないので,使いやすさを損ねる原因になりかねません。

 そうしたページの代表として,例えば掲示板のようなものが挙げられるでしょう。こうしたページでは,書き込みを行うと,その書き込みが追加された(最新の)書き込み一覧のページが表示されます。そして,そのページは,その後誰かによってさらに書き込みが行われる可能性が高くなっています。したがって,書き込みを行った人が,さらにそのページを再読み込みして,新たな書き込みがないかをチェックする可能性は高いわけです。その際に,たとえ2重投稿が防止されていたとしても,図3のようなダイアログがいちいち出てしまうのは,ちょっとうれしくありません。リダイレクトを挟むことで,再読込をしても,単にGETのアクセスが発生するだけの状況を作り,いちいちメッセージが表示されてしまうことを防ぐことができます。

 これらのことを考えると,PRGパターンというのは,POSTの結果として表示したいページが再読込みされやすい場合に,特に有効だといえます。おそらくそうしたページは,例えば掲示板の「最新の書き込み」のページのように,別にPOSTによってデータを送らない場合でも,単なるGETアクセスによって同じ情報のページにアクセスができる場合が多いと思います。

 そんなとき,POSTの結果と通常のアクセスで,別のURLで同じ情報が見えるというのはあまり好ましくありません。POSTの結果は情報をサーバー側で記録する機能だけを持ち,そこから,表示のためのページへリダイレクトする,というのは理にかなっています。「お気に入り」やソーシャルブックマークにそれぞれが別々のページとして登録されてしまうといったことも起こりませんし,ウェブ・アプリケーション側でも,同じ情報が一つのURLのみで表示されるほうが,処理が簡単になるはずです(図4)。

図4:同じ情報は一つのURLのみに表示される

 逆に,リロードされる可能性がそれほど高くないような,一過性のページ,例えば「情報を登録しました」というメッセージが表示され,どこかに移動するだけのページなら,リダイレクトする必要はなく,単にセッションを管理して二重登録さえ防止すればいいような気もします。つまりPRGパターンを利用するかどうかは,そのページが再読み込みされるかどうかが判断ポイントとなりそうですね。