画像やスクリプトなどの外部ファイル取り込みを高速化するために、キャッシュ制御は不可欠です。
しかし、設定をうっかりすると(あるいは、しないと)、キャッシュが強すぎて全くデータが更新されないような場合があります。
今回のキーワードは、「IE」と「F5キー」、そして「XMLHttpRequest」。
「」の著者であるStevesSuders氏のblogで紹介された「F5 and XHR deep dive」を検証してみます。
「F5」でXHR通信結果が更新されない
通常、キャッシュが設定された外部ファイル取り込みは、その期限が来るまでは再通信されません。しかしブラウザをF5やCtrl+rなどで明示的にリロードした場合はその限りではなく、ファイルの再取得が行われるのが一般的です。
しかし、キャッシュ指定の条件によっては、XMLHttpRequestを用いた、いわゆるAjax通信時が発生しなくなってしまうとHttpWatchの記事で伝えられました。
これを検証するために、簡単なプログラムを作ってみます。
検証プログラムの説明
まずは、取り込まれるjsファイルを用意します。
サーバサイドで毎回ジェネレートされる、現在時刻を指定された要素に出力するだけのスクリプトです。
呼び出す度に日時が更新されることが分かると思います。
そして必要なのはキャッシュコントロール。
パケット監視などが出来る人は見ていただけばわかるのですが、パラメータに応じて次のようなヘッダを付与します。
- cache=1
- キャッシュ有効。Expiresを30日後にし、Cache-Controlのmax-ageも30日間に設定します。
- cache=-1
- キャッシュ無効。Expiresを30日前にし、Cache-Controlのmax-ageは0とします。
- cache=0
- キャッシュ指定無し。ExpireもCache-Controlも指定しません。
ついでに、画像も用意してみました。同様にサーバサイドで現在時刻の画像を作成して返します。キャッシュ制御も同じです。
これを、テスト用のHTMLで取り込みます。
スクリプトは、scriptタグによる単純な取り込みと、XMLHttpRequestによるAjax通信の2種類。画像はimgタグで指定しています。
前述の3種類のキャッシュ制御を行うページは、次の通りです。
これで、ページを開いた時の時刻(正確には、サーバがリクエストを受け付けた時刻)が表示されるはずです。リロードや再訪問時に、キャッシュが効いていれば日時はキャッシュされた時のままになります。
順に見ていきましょう。
キャッシュ無効の場合
通常遷移 | F5リロード | |||||
---|---|---|---|---|---|---|
Image | Script | XHR | Image | Script | XHR | |
Chrome2 | 更新 | 更新 | 更新 | 更新 | 更新 | 更新 |
FF3.0 | 更新 | 更新 | 更新 | 更新 | 更新 | 更新 |
FF3.5 | 更新 | 更新 | 更新 | 更新 | 更新 | 更新 |
Opera9 | 更新 | 更新 | 更新 | 更新 | 更新 | 更新 |
Opera10 | 更新 | 更新 | 更新 | 更新 | 更新 | 更新 |
IE6 | 更新 | 更新 | 更新 | 更新 | 更新 | 更新 |
IE7 | 更新 | 更新 | 更新 | 更新 | 更新 | 更新 |
IE8 | 更新 | 更新 | 更新 | 更新 | 更新 | 更新 |
Safari3 | 更新 | 更新 | 更新 | 更新 | 更新 | 更新 |
いずれの場合も期待通り、キャッシュは全くききませんでした。
ページ遷移を行った場合も、F5でリロードした場合も、全て最新に更新されます。
キャッシュ有効の場合
通常遷移 | F5リロード | |||||
---|---|---|---|---|---|---|
Image | Script | XHR | Image | Script | XHR | |
Chrome2 | キャッシュ | キャッシュ | キャッシュ | 更新 | 更新 | 更新 |
FF3.0 | キャッシュ | キャッシュ | キャッシュ | 更新 | 更新 | 更新 |
FF3.5 | キャッシュ | キャッシュ | キャッシュ | 更新 | 更新 | 更新 |
Opera9 | キャッシュ | キャッシュ | キャッシュ | 更新 | 更新 | キャッシュ |
Opera10 | キャッシュ | キャッシュ | 更新 | 更新 | 更新 | 更新 |
IE6 | キャッシュ | キャッシュ | キャッシュ | 更新 | 更新 | キャッシュ |
IE7 | キャッシュ | キャッシュ | キャッシュ | 更新 | 更新 | キャッシュ |
IE8 | キャッシュ | キャッシュ | キャッシュ | 更新 | 更新 | キャッシュ |
Safari3 | キャッシュ | キャッシュ | キャッシュ | 更新 | 更新 | 更新 |
動作が分かれました。
通常にページ遷移を行った場合は、Opera10を除き一律にキャッシュが使われる期待通りの動作です。(Opera10はまだbetaのため、最終的にどういった仕様になるかは不明です)
F5などでリロードを行うと、画像やscript要素で取り込んだものは、いずれも再読み込みされます。
しかしXMLHttpRequestでの通信は、ChromeやFFでは再通信が行われるのに対し、IEとOpera9ではそのままキャッシュが有効になってしまいました。これはCtrl+F5のようなスーパーリロードを用いても、変わりません。
キャッシュ指定無しの場合
通常遷移 | F5リロード | |||||
---|---|---|---|---|---|---|
Image | Script | XHR | Image | Script | XHR | |
Chrome2 | 更新 | 更新 | 更新 | 更新 | 更新 | 更新 |
FF3.0 | 更新 | 更新 | 更新 | 更新 | 更新 | 更新 |
FF3.5 | 更新 | 更新 | 更新 | 更新 | 更新 | 更新 |
Opera9 | キャッシュ | キャッシュ | 更新 | 更新 | 更新 | 更新 |
Opera10 | キャッシュ | キャッシュ | キャッシュ | 更新 | 更新 | キャッシュ |
IE6 | 更新 | 更新 | キャッシュ | 更新 | 更新 | キャッシュ |
IE7 | 更新 | 更新 | キャッシュ | 更新 | 更新 | キャッシュ |
IE8 | 更新 | 更新 | キャッシュ | 更新 | 更新 | キャッシュ |
Safari3 | 更新 | 更新 | 更新 | 更新 | 更新 | 更新 |
かなり無軌道になっています。Operaに至っては、通常のページ遷移でも動作に違いが出てしまいました。
ETagについて
StevesSuders氏の検証ではETagについても含まれています。
今回は検証結果を見やすくするために、レスポンス304については確認していません。
氏のページによれば、Safari4はIf-Modified-Sinceを送らずに常に再送信されてしまうようです。
まとめ
- Expiresを指定しないことは、動作を全く制御しないのと同じこと。可能な限りきちんと、用途にあわせてキャッシュの制御を行うべきです。
- Ajax通信でキャッシュをされたくない場合(多くの場合、この用途でしょう)、Expiresを過去に指定してキャッシュを無効にしましょう。
- 或いは、通信にエポックタイムのようなユニークなIDをパラメータに付与し、キャッシュできないようにするのも良い方法です。
- Ajax通信をキャッシュしたい場合、Expiresをキャッシュしたい期間、きちんと指定しましょう。ただし、その際にはF5でリロードしても更新されないブラウザがいることを知っておきましょう。
- Operaを対応ブラウザにするならば、バージョン10がどのような仕様になるか注意しておきましょう。
Related posts: