« 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サーバーのログを見たところ、次の結果となった。

【結果１：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＞

------------------------------------------------------------------------------

結果は、次のとおり。

【結果２：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回目のアクセスではやはりローカルキャッシュを見ているのだろう。

結果１と結果２から総合すると、IE6SP1の動きは、「If-Modified-Sinceを付加しない場合、たとえWebページが更新されていても、何度アクセスしてもローカルキャッシュを見に行く。」ように見える。

最後に、スクリプトの「var last_modified = null;」の部分を「var last_modified = "Thu, 01 Jun 1970 00:00:00 GMT";」と変更して再度テストを試みた。

結果は、次のとおり。

【結果３：1回目からIf-Modified-Sinceをつける】

・IE6 SP1の場合

1回目のアクセス→ステータスコード200でGET

2回目以降のアクセス→ステータスコード304でGET

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



結論としては、

「ブラウザ（Javascript）に任せず、If-Modified-Sinceの処理は自分で明示的にコーディングすべし」

となる（当たり前？）。

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



補遺

Ajaxアプリケーション作成の際、結果３の方法は十分ではない。それは、結果２においてfirefoxを「それなりの動き」と表現した理由でもある。

上記のスクリプトでは、単純なHTTPリクエストのほかに次のことを実施している。

1) Last-Modified情報の保存（次にIf-Modified-Sinceに利用するため）

2) Webページの内容のキャッシュ

これに加えて、本来は、

3) 1)と2)で保存した内容の永続化（ブラウザを再起動しても前回の内容が保存されている）

が必要だ。

上記のスクリプトでは、3) ができていないので、「ブラウザをリロードしたらJavascriptが再スタートし、保存しておいたLast-Modified情報がリセットされてしまう」問題を抱えている。この問題を解決するには、次の２つが必要だ。

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

コメントしてください