XMLHttpRequestによるステータスコード304の取り扱い
【前提知識として】
あるリソースにHTTPリクエストを行ったときに、そのリソースに変更がない場合はステータスコードとして304を返します。
このステータスコード304の場合はリクエストボディにデータを入れないのが原則なのでデータ通信量が減り、余計なトラフィックを減らすというのが目的の一つみたいです。
そして304を受け取ったクライアント(ブラウザ)はクライアントキャッシュから対象のリソースを読み込んで表示します。
基本的には200(リクエストOK)と304(変更ないからクライアントキャッシュを使用しろ)はブラウザ使用者からしてみれば表示内容は同じです
【やりたいこと】
Ajaxを利用したアプリケーションを作成しているときに200と304でクライアントの挙動を変えたい
コンテンツを取得しにXMLHttpRequestでリクエストを投げた時にサーバー側では
- コンテンツに追加書き込みなどがあれば、その内容をセットして200を返す。
- コンテンツに追加書き込みがなければ、304を返す。
クライアント側は
- 200だったら画面を更新する
- 304だったらなにもせずにjavascript実行を終了する
をやりたい。
期待するメリットは
- 更新チェックを裏側で(Ajaxで)行い、変更がなかった場合(304の場合)クライアントで余計な描画処理をしないようにする
(ちなみにexpiresによるクライアントキャッシングも同時に行います)
【問題】
XMLHttpRequestオブジェクトにはステータスコードを持つプロパティとしてXMLHttpRequest.statusがあります。
しかしこのプロパティが曲者。
サーバーで304をセットしても、返却されるXMLHttpRequest.statusには200がセットされてしまっていますort
なので200と304で挙動を変更することはできません。
http://wingerz.com/blog/2006/07/01/304-or-200/
のコメント欄には
サーバー>>>ブラウザ>>>XMLHttpRequestエンジン
という順番で通知されるということが解説されていて、ブラウザが304を受け取った時点でブラウザキャッシュをセットしてXMLHttpRequestエンジンには200として通知していると言っています。
(本当かどうかはわかりませんが納得はできます)
以下実験した結果です。
ローカルのApacheにtest.xmlというファイルを置いて、そのファイルにXMLHttpRequestでアクセスする
Apacheの設定で
LoadModule expires_module modules/mod_expires.so ExpiresActive onExpiresDefault "modification plus 2 minute"
を設定してexpiresを2分間に設定。
初回リクエスト | expires時間内に再リクエスト | expires時間経過後に再度リクエスト | もう一回リクエスト(test.xmlが更新されない限りexpiresも更新されないらしい) | ファイル更新してリクエスト | |
---|---|---|---|---|---|
サーバーで返すステータスコード(apacheのaccessログで確認) | 200 | ログなし(クライアントキャッシュを表示) | 304 | 304 | 200 |
XMLHttpRequest.statusの値 | 200 | 200 | 200 | 200 | 200 |
※IE6、FF2、OPERA9.1で全部同じ結果
実験用コードは以下
<html> <head> <script language="javascript" type="text/javascript"> var testFunc = function() { var getTransport = function() { return Try.these( function() {return new XMLHttpRequest()}, function() {return new ActiveXObject('Msxml2.XMLHTTP')}, function() {return new ActiveXObject('Microsoft.XMLHTTP')} ) || false; } var req = getTransport(); req.onreadystatechange = function() { alert("state=" + req.readyState + "&statusCode=" + req.status); } req.open('GET', 'http://test.co.jp/test.xml' ,true); req.send(""); } </script> </head> <body> <input type="button" onclick="testFunc();" /> </body></html>
しかしネットでいろいろ調べているとprototype.jsにはAjax.Requestのプロパティとしてon[ステータスコード]として関数を渡して、任意のステータスコード時の振る舞いができるのでon304と書けば挙動をコントロールできるという情報がいくつか出てくる。
実際に動かして試した人がいるんだろうか・・・
知ってる人がいたら教えてください。