« RSSにどこまで書くか | メイン | [RNA] HTTPコード301 によるRSS移転に対応 »

April 07, 2005

[Ajax tips] XMLHttpRequest と If-Modified-Since

RSSリーダーについてさんざん言及されたように、Webコンテンツを取得するアプリケーションでは、 HTTPリクエストに If-Modified-Since ヘッダ をつけるなどして対象コンテンツの更新時刻をチェックし、過剰なデータ取得を避けるのがマナーであるとされている。

同じことがAjaxについても当てはまると考える。Ajaxでは、ユーザーのアクションと非同期にHTTPリクエストを行うため、RSSリーダーと同様に人為操作を超えるトラフィックを発せさせる可能性があるからだ。

そこで、素朴な疑問。
 ・ブラウザは、ユーザーが意識しないでも更新時刻チェックをやってくれる。
 ・Ajaxの主なエンジンとなる Javascript は、ブラウザに組み込まれたものである。
 ・Javascript の XMLHttpRequestを使用すると、プログラマが明示的にコーディングしなくても、更新時刻チェックを実行してくれるのではないか。

というわけで、簡単な実験をしてみた。概要は次のとおり。
 1) XMLHttpRequestで適当なWebページを数回GET
 2) Webサーバのログをみて、更新時刻チェックしているかチェック
なお、対象Webページは、「ブラウザで以前アクセスしたことがあるが、最終更新日時以降はアクセスしていない」状態である。
また、テスト内容は完全なものではなく、あらゆる環境および状況で同様の結果が得られることを保証するものではないのであしからず。

以下、詳細と結果。
まず、次のようなテスト用Webページを設置。
index.htmlというHTMLファイル(なんでもいい)を、XMLHttpRequestでGETするだけのJavascriptスクリプトだ。
------------------------------------------------------------------------------
<html>
<head>
<script type="text/javascript">
function testfunc() {
 var xmlhttp = false;
 if (typeof XMLHttpRequest!='undefined')
  xmlhttp = new XMLHttpRequest();
 else
  xmlhttp = new ActiveXObject("MSXML2.XMLHTTP");

 xmlhttp.open("GET", 'index.html', false);
 xmlhttp.send(null);

 document.getElementById("r").innerHTML=xmlhttp.getAllResponseHeaders();
 document.getElementById("c").innerHTML=xmlhttp.responseText;
}
</script>
<title>ajax If-Modified-Since test</title>
</head>
<body>
<button onclick="testfunc()">click!</button>
<hr />
<pre id="r"></pre>
<hr />
<div id="c"></div>
</body>
</html>
------------------------------------------------------------------------------

このWebページのボタンを数回クリックして、Webサーバーのログを見たところ、次の結果となった。
【結果1:If-Modified-Since未コーディング】
・firefox1.0.2の場合
 1回目のアクセス→ステータスコード200でGET
 2回目以降のアクセス→ステータスコード200でGET
・IE6 SP1の場合
 1回目のアクセス→ロギングされない
 2回目以降のアクセス→ロギングされない

firefoxでは、更新時刻チェックを行ってくれないようだ。
IEでは、なぜかWebサーバにアクセスしていないようだ。しかし、XMLHttpRequest.responseTextには値が入っている。ブラウザのローカルキャッシュをそのまま入れているように見受けられる。ブラウザのローカルキャッシュ(インターネット一時ファイル)をいったん削除して、再度テストを行うと、1回目だけは200でGETしてくるが、2回目以降はやはりWebサーバにアクセスしない。ここまではいいが、Webページを編集して更新時刻を変更してから再度テストしても、Webサーバにアクセスせずにローカルのキャッシュを取得し続けてしまう。テストの仕方が悪いのだろうか。この動きはAjaxアプリケーション作成時にやっかいだ。

そこで、こんどは明示的にIf-Modified-Sinceによる更新時刻処理をコーディングしてみた。Webページのスクリプト部分を次のように変更して、再度テストを実施。
(ロジックはきれいじゃないが。。。)
------------------------------------------------------------------------------
<script type="text/javascript">
var last_modified = null; /*← この行を追加*/
var cached_content = ''; /*← この行を追加*/
function testfunc() {
 var xmlhttp = false;
 if (typeof XMLHttpRequest!='undefined')
  xmlhttp = new XMLHttpRequest();
 else
  xmlhttp = new ActiveXObject("MSXML2.XMLHTTP");

 xmlhttp.open("GET", 'index.html', false);
 if(last_modified) /*← この行を追加*/
  xmlhttp.setRequestHeader("If-Modified-Since", last_modified); /*← この行を追加*/
 xmlhttp.send(null);

 document.getElementById("r").innerHTML=xmlhttp.getAllResponseHeaders();
 document.getElementById("c").innerHTML=xmlhttp.responseText;
 if(xmlhttp.getAllResponseHeaders().match("Last-Modified")) /*← この行を追加*/
  last_modified = xmlhttp.getResponseHeader("Last-Modified"); /*← この行を追加*/
 if(xmlhttp.responseText.length == 0) /*← この行を追加*/
  document.getElementById("c").innerHTML = cached_content; /*← この行を追加*/
 else /*← この行を追加*/
  cached_content = xmlhttp.responseText; /*← この行を追加*/
}
</script>
------------------------------------------------------------------------------
結果は、次のとおり。
【結果2:If-Modified-Sinceチェックを明示的にコーディング】
・firefox1.0.2の場合
 1回目のアクセス→ステータスコード200でGET
 2回目以降のアクセス→ステータスコード304でGET
・IE6 SP1の場合
 1回目のアクセス→ロギングされない
 2回目のアクセス→ステータスコード200でGET
 3回目以降のアクセス→ステータスコード304でGET

firefoxでは、それなりの動きになった。
IEでは、firefoxよりワンテンポ遅れたような動きになっている。1回目のアクセスではやはりローカルキャッシュを見ているのだろう。
結果1と結果2から総合すると、IE6SP1の動きは、「If-Modified-Sinceを付加しない場合、たとえWebページが更新されていても、何度アクセスしてもローカルキャッシュを見に行く。」ように見える。

最後に、スクリプトの「var last_modified = null;」の部分を「var last_modified = "Thu, 01 Jun 1970 00:00:00 GMT";」と変更して再度テストを試みた。
結果は、次のとおり。
【結果3:1回目からIf-Modified-Sinceをつける】
・IE6 SP1の場合
 1回目のアクセス→ステータスコード200でGET
 2回目以降のアクセス→ステータスコード304でGET

上記のとおり、firefoxと同じ動きになった。


結論としては、
「ブラウザ(Javascript)に任せず、If-Modified-Sinceの処理は自分で明示的にコーディングすべし」
となる(当たり前?)。

追記:If-Modified-Sinceを使用してキャッシュを行うXMLHttpRequestラッパーを書いてみた。


補遺
Ajaxアプリケーション作成の際、結果3の方法は十分ではない。それは、結果2においてfirefoxを「それなりの動き」と表現した理由でもある。
上記のスクリプトでは、単純なHTTPリクエストのほかに次のことを実施している。
 1) Last-Modified情報の保存(次にIf-Modified-Sinceに利用するため)
 2) Webページの内容のキャッシュ
これに加えて、本来は、
 3) 1)と2)で保存した内容の永続化(ブラウザを再起動しても前回の内容が保存されている)
が必要だ。
上記のスクリプトでは、3) ができていないので、「ブラウザをリロードしたらJavascriptが再スタートし、保存しておいたLast-Modified情報がリセットされてしまう」問題を抱えている。この問題を解決するには、次の2つが必要だ。
 i) Javascriptからブラウザのローカルキャッシュ情報(Last-Modifiedなど)にアクセスできること
 ii) XMLHttpRequestでWebコンテンツを取得した場合でも、ブラウザのローカルキャッシュに追加されること
この面については、IEの動きはある意味firefoxより優れている気がする。しかし、対象Webページが更新されていてもIf-Modified-Sinceをつけないかぎりローカルキャッシュを常に見るという動きはなんとかしてほしいところだ。

Ajaxアプリケーションが普及するためには、以上のような処理を、プログラマが意識することなくブラウザ(Javascriptインタプリタ)が調整してくれることが望ましい。何かやり方があるのだろうか。

投稿者 msano : April 7, 2005 11:09 PM

トラックバック

このエントリーのトラックバックURL:
http://www.semblog.org/mt3/mt-tb.cgi/296

このリストは、次のエントリーを参照しています: [Ajax tips] XMLHttpRequest と If-Modified-Since:

» Ajax と If-Modified-Since from blog.bulknews.net
msanolog: [Ajax tips] XMLHttpRequest と If-Modified-Since 同じことがAjaxについても当てはまると考える... [続きを読む]

トラックバック時刻: April 9, 2005 11:49 PM

» その他ごちゃおき from PukiWiki/TrackBack 0.1
その他ごちゃおきスペース なんでもいいから置いておけ http://blog.i-know.jp/archives/2005/03/29/ajax/ Ajaxミ... [続きを読む]

トラックバック時刻: April 10, 2005 12:32 AM

» 【Ajax】If-Modified-Sinceは明示的にコーディングすべし from JavaScript++かも日記
[Ajax tips] XMLHttpRequest と If-Modified-Since Javascript の XMLHttpRequestを使用すると... [続きを読む]

トラックバック時刻: April 21, 2005 03:48 PM

» Firefox でのローカルキャッシュと If-Modified-Since from 鷹の島
ScrapMemo は静的 XML ファイルを扱ってるわけでして、そうなると、やっぱり更新時刻のチェックとかローカルキャッシュの事も考えないといけないわけなので... [続きを読む]

トラックバック時刻: May 12, 2005 04:02 PM

» XMLHttpRequest と If-Modified-Since from ゆうすけブログ (BIGLOBE)@WebryBlog
手元の環境でXMLHttpRequestによる静的XMLファイルのダウンロード時の ブラウザキャッシュの使用状況を確認したところ、  ・Internet E... [続きを読む]

トラックバック時刻: May 26, 2005 01:01 AM

» 【Ajax】関連リンク from JavaScript++かも日記
【アプリ&実験】 Google Maps http://maps.google.com/ Google Suggest http://www.google.co... [続きを読む]

トラックバック時刻: June 11, 2005 12:03 AM

» AJAX関連記事(メモ) from Over 40
解説記事(日本語) はてなダイアリー - Ajaxとは IT用語辞典 e-Wor... [続きを読む]

トラックバック時刻: June 23, 2005 11:53 AM

コメント

うーん、httpにはIf-None-Matchもあるし、クライアントとはいえJavaScript側でこのあたりにいちいち対応するのは厳しいでしょう。。。
サーバー側のLast-ModifiedやEtagの取り扱いにも振り回されるし。。。

> プログラマが意識することなくブラウザ(Javascriptインタプリタ)が調整してくれることが望ましい。
というのに同意ですね。そのときにはもうxmlhttpとは違うモノになる可能性もなきにしもあらずですが。

投稿者 Ryosuke : April 11, 2005 09:29 AM

主題ではないですが、、、
XmlHttpRequestは仕様上、同サーバーにしかアクセスできないので、If-Modified-Sinceを付けると言うのはマナーと言うよりも自分自身の首を絞めない為って感じですか

それと、ローカルキャッシュの件は大変な落とし穴ですが、もしかしたらSajaxやRuby on Rails等のフレームワーク部分で対応してくれるたりしないかなぁ(現状未確認)

投稿者 bo : April 11, 2005 09:57 AM

「ソフトウェア作成者」のせいで「利用者」が「サーバ管理者」にアタックしてしまう構図になります。結果として、「サーバ管理者」が「利用者」に制限をかけてしまい、「利用者」がソフトウェアを使用しなくなることが予想されるので、「作成者」にとっても自分のためにちゃんとしないといけないということですね。

投稿者 msano : April 12, 2005 01:17 AM

lake powell

投稿者 lake powell : April 13, 2005 09:08 PM

pmgmentors
pmg mentors
prosperlearning
prosper learning
http://realestate.pmgmentors.com

投稿者 pmgmentors : April 14, 2005 05:40 AM

weight loss
weight loss supplements
weight loss nutrition
weight loss products
fast weight loss
quick weight loss
weight loss dietary supplements
http://www.healthierweightloss.com/shop/default.php

投稿者 weight loss nutrition : April 14, 2005 06:11 AM

コメントしてください




保存しますか?