読者です 読者をやめる 読者になる 読者になる

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 on
	
	ExpiresDefault "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と書けば挙動をコントロールできるという情報がいくつか出てくる。

実際に動かして試した人がいるんだろうか・・・
知ってる人がいたら教えてください。



【追記】
http://d.hatena.ne.jp/flick-flick/20071217