HTTP の GET メソッドと POST メソッドについて、改めて書きたいことがあります。定義の中のある箇所が世間では軽視されているように思うのです。
Wikipedia に簡潔かつ正確に解説されている話ですが、ここで改めて解説を。
http://ja.wikipedia.org/wiki/%E5%86%AA%E7%AD%89#WWW
HTTP 1.1 の通信手順・動作を定義している RFC 2616 http://www.ietf.org/rfc/rfc2616.txt に「9.1.2 Idempotent Methods」という節があります。
"Idempotent" の形容詞 "Idempotence" とは「N(>0)回実行された際の副作用が、1回のみ実行された際の副作用と同じ」と定義されています。平たく言うと、1回目の実行で何か変化が起きる(かもしれない)のですが、2回目以降の実行では変化が起きないという意味です。日本語では「冪等」と訳されます。これは数学用語で、一般の英和辞典には見つかりません。
RFC 2616 では GET、HEAD、PUT、DELETE が Idempotent Methods であり、また OPTIONS、TRACE は副作用を持つべきではないと定義しています。裏を返すと POST は Idempotent Methods ではありません。
この定義はブラウザやプロキシサーバのキャッシュに影響します。2回目以降に変化が起きないリクエストは、キャッシュを使って回数を減らして構いません。リクエストの度に変化が起きるメソッドは、キャッシュを使って回数を減らすと結果が変わってしまいます。
つまり GET メソッドの結果はキャッシュしてもいいですが、POST メソッドの結果はキャッシュしてはいけません。
Web プログラミングに詳しい人なら、GET メソッドの度に状態を変化させるプログラムを CGI/PHP 等で作れることを知っているでしょう。アクセス回数を数えるアクセスカウンタはそうして作られています。文書で決めることに意味がないと考える方もいらっしゃるかもしれません。
しかし GET と POST の違いを決めておくことに意味があります。目的に応じて使い分ける基準になります。さらには、世に広まっているブラウザやプロキシサーバのキャッシュはこの定義に従って実装されているので、Web アプリを開発する際に定義に逆らうとキャッシュ制御でトラブルを起こしやすいんです。
キャッシュして欲しいデータを POST で取得するようにプログラミングするとキャッシュが効かなくて困るようになります -よくある「フォームの期限切れ」- し、キャッシュされては困るデータを GET で取得するようプログラミングするとキャッシュの無効化を考えなければなりません。アクセスカウンタは HTML に埋め込みたいので GET メソッドで取得しますが、キャッシュの動作から考えると例外的です。
キャッシュのコントロールを考えたときに、GET と POST を使い分けてキャッシュの動作を変える方法もあるのです。
>世に広まっているブラウザやプロキシサーバのキャッシュはこの定義に従って実装されているので
これは興味深い情報だと思うのですが、具体的にはどのブラウザ・プロキシサーバのことをおっしゃっているのでしょうか?
慌てて資料をかき集めましたが、GET と POST の違いにふれたものはほとんどありません。おそらく mm さんは具体例を見ないと信用できない方ではないでしょうか。すると論争になりそうなのですが、詳細は後述
Internet Explorer (IE) の資料は
[HOWTO] Internet Explorer でキャッシュを無効にする
http://support.microsoft.com/kb/234067
ここに GET と POST の区別は書かれていません。でも、難しい話は抜きにして、バックボタンで戻ろうとしただけで「フォームの有効期限が過ぎています...」というダイアログが出る、それが GET と POST の区別です。
Firefox の場合は
HTTP Caching FAQ - MDC
http://developer.mozilla.org/en/docs/HTTP_Caching_FAQ
ここにも GET と POST の話は書かれていません。Mozilla 系列の特徴である「RFC/W3C 勧告からなるべく不足も過剰も設けない」がキャッシュでどこまで一貫しているかという問題に...
携帯電話の場合、
au は
KDDI au: XHTML Basic について > キャッシュコントロール
http://www.au.kddi.com/ezfactory/tec/spec/wap_tag11.html
デフォルトでは、GET は有効期間が残り 30 日とみなされますが、POST は有効期間がマイナス、つまり表示されたときにはすでにキャッシュは古いとみなされます。
ソフトバンクでは SoftBank 6-2 シリーズの仕様として GET と POST を区別します。Jフォン当時からのシリーズなので、昔からそうだったのでしょう。6 シリーズの初期に POST をキャッシュする端末がありますが、後継端末では元に戻っています。
http://developers.softbankmobile.co.jp/dp/tool_dl/web/tech.php から
ウェブ HTTP 編 の PDF ドキュメントをダウンロード
3G シリーズが明記されていなくて...
ドコモの資料がうまく見つかりません。
さて、mm さんへの話の続きはどうしましょう。
mm さんがブラウザのユーザとして聞きたいという話なら、今すぐにはいい言葉が思いつきません。
ウェブサイトの管理人として聞きたいという話なら、事がキャッシュコントロールになると、むしろ抽象的に考えなければうまくいかないと僕は思っています。
ブラウザの差違よりも利用者の使い方の差違の方が大きくなる特徴があるからです。
ユーザがどれだけキャッシュ容量を割り当ててページをどのくらい閲覧してくるのかは管理人が管理できません。
センセーショナルな話をすれば「萌え画像をたくさん見たらディスクキャッシュが埋まってしまったwww」という利用者が来ることだってあります。
となると、「キャッシュしてほしいけれどもリクエストしてきた場合」と「リクエストしてほしいけれどもリクエストがなかなか来ない場合」のそれぞれを考えて、各パターンに対処していかないとうまくいきません。そうしたらブラウザの差違はその中に消えてしまう、と思っています。
その対処は難しくて、RFC 2616 をほぼフル実装するか、リクエストしてほしいコンテンツだけ Cache-Control: no-cache を付ける単純化の極北か、結局は両極端しかうまくいかないということになりがちなんですが。
今、見つけた資料と自分の考えをまとめるとこんなところです。
やはりこの手の問題は個別実験して調査するのがベストと思いますが、規格等で統一された原則があるのか気になっていたものですから。
記事・コメントとも参考にさせていただきます。本当にありがとうございます。
POSTリクエストに対するレスポンスが一般にキャッシュされないのは知っていましたが、こういう理由があったのですね。