リダイレクトとmethodの微妙な関係

Webアプリにおいて,データベースへの更新処理の後に一覧表示画面に戻る,という画面遷移はほとんどのアプリケーションで見受けられる基本的なものだ。この画面遷移,何も考えずにStrutsなどで作ってしまうと,後で問題が発生する。

その問題とは,「F5問題」だ。更新処理後に表示される一覧表示画面で,Webブラウザのページ再更新機能([更新]ボタン押下やF5キー押下など)を実行すると・・・という場面の話である。通常,Strutsなどでは,「更新処理」アクションから「一覧表示用情報取得」アクションを呼び出して,更新処理と一覧表示のための情報取得処理を連続し,一覧表示画面用のJSPにフォワードさせる。この際,「更新処理」アクションから「一覧表示用情報取得」アクションをどう連続させているかが問題となる。

「更新処理」アクションから「一覧表示用情報取得」アクションをフォワードで呼び出していた場合,Webブラウザからすれば,「更新処理を呼び出した結果,一覧表示画面が返ってきた」ということになる。そうなると,一覧表示画面でF5きーを押したときには,Webブラウザが記憶している一つ前に送信したリクエスト,つまり「更新処理」が再度サーバに送信されてしまう。ユーザからすれば,一覧を更新したかっただけなのに,更新処理が行われてしまうのは,全く予期しない動作であり,かなりの問題となる。

これは,リダイレクトというテクニックを使用すれば解決する。「更新処理」アクションが終わった後に,「一覧表示用情報取得」アクションをフォワードで直接呼び出してしまうのではなく,一旦「『一覧表示用情報取得』アクションを呼び出してね」と制御をWebブラウザに戻す。再要求のリクエストを受け取ったWebブラウザは,自動的に「一覧表示用情報取得」アクションを呼び出すためのURIをWebサーバに発行する。この動きであれば,一覧表示画面でF5キーを押したときに判断される一つ前のリクエストは,更新処理ではなく,一覧表示になるので,更新処理は行われずに一覧表示だけが再表示されるようになり,めでたしめでたしとなる。

・・・と思っていたが,リダイレクトはもっと奥が深い。

このリダイレクト,実際にはサーバからWebブラウザに HTTPステータスコードが返却されることによって実現されている。リダイレクトを想定したコードは,以下のものが代表的だ。

  • 301 MovedPermanently 恒久的に移動しました

  • 303 See Other ほかを参照してください

  • 307 Temporary Redirect 一時的なリダイレクトです

上記のHTTPステータスコードと共に,HTTPレスポンスヘッダのLocationヘッダ項目でURIが指定される。Webブラウザは受信したHTTPステータスコードを判断し,LocationヘッダのURIに対して自動的に要求を行うことで,リダイレクトが実現される。

上記のステータスコードによって,Webブラウザは若干違った動きを見せる。301と303の場合,Locationヘッダで指定されたURIに要求を行うとき,method はGETが使用される。しかし,307の場合は,307を受け取る原因となった元々の要求がPOSTで行われていたときは,Locationヘッダで指定されたURIに要求を行うときもPOSTが使用される。

例えばLocationヘッダのURIに,「http://~/showEmployeeList.do?div=2」というようにパラメータが付与されていた場合,リダイレクト後のWebブラウザのアドレスバーには,元々の要求がGETの場合はこのURIが,POSTの場合は「http://~/showEmployeeList.do」までが表示される。そして,POSTだった場合は,F5キー押下などによる再読み込み時には,「再度フォーム情報を送ることになるけど,いいの?」という内容の警告ダイアログがWebブラウザにより表示されることになってしまう。この動きは,時としてユーザビリティという面で顧客から問題視されてしまうことがある。

自分でHTTPをお話すれば,上記のステータスコードの使い分けができるのだが,Javaで開発している場合は,HttpServletResponse#sendRedirect() を使用してリダイレクトを行っていることだろう。この場合は,sendRedirect() の実装がどうなっているかによって,どのステータスコードが使われるかが決定する。つまり,サーブレットコンテナの実装に依存してしまうのだ。

Tomcat4.1.31の実装では,307が使われている。つまり,元々の要求がPOSTだった場合は,POSTを使ってリダイレクトが行われる。そして,他のステータスコードを使用してのリダイレクトを行いたいとしても,切り替えられるような設定はできないみたいだ。ソースコードが見れるコンテナなら調べられるが,商用のアプリケーションサーバでは,HTTPをお話しするプログラムやプロキシを作成するなどして,自分でプロトコルを覗く必要がある。

悩ましい問題だ。。。

このエントリーをはてなブックマークに追加

関連記事

2023年のRemap

Remapにファームウェアビルド機能を追加しました

Google I/O 2023でのウェブ関連のトピック

2022年を振り返って

現在のRemapと今後のRemapについて