アプリケーション キャッシュの使用に関する初心者向けガイド

はじめに

ウェブベースのアプリケーションをオフラインで利用できるようにすることがますます重要になっています。はい。すべてのブラウザは、指示された場合、ページとリソースを長期間キャッシュに保存できますが、ブラウザはいつでも個々のアイテムをキャッシュから削除して、他のアイテムのためのスペースを確保できます。HTML5 では、ApplicationCache インターフェースを使用して、オフライン状態のデメリットの一部を解消しています。キャッシュ インターフェースを使用すると、アプリケーションに次の 3 つのメリットがあります。

  1. オフライン ブラウジング - ユーザーはオフラインでもサイト全体を閲覧できます
  2. 速度 - リソースはディスクから直接取得され、ネットワークにアクセスする必要はありません。
  3. 復元力 - 「メンテナンス」のためにサイトがダウンしても(誰かが誤ってすべて壊してしまった場合など)、ユーザーはオフラインで利用できます

アプリケーション キャッシュ(AppCache)を使用すると、デベロッパーはブラウザがキャッシュに保存し、オフライン ユーザーが利用できるようにするファイルを指定できます。ユーザーがオフライン中に更新ボタンを押しても、アプリは正しく読み込まれて動作します。

キャッシュ マニフェスト ファイル

キャッシュ マニフェスト ファイルは、オフライン アクセス用にブラウザがキャッシュに保存するリソースを一覧表示するシンプルなテキスト ファイルです。

マニフェスト ファイルの参照

アプリのアプリケーション キャッシュを有効にするには、ドキュメントの html タグにマニフェスト属性を含めます。

<html manifest="example.appcache">
  ...
</html>

manifest 属性は、キャッシュに保存するウェブ アプリケーションのすべてのページに含める必要があります。manifest 属性が含まれていない場合、ブラウザはページをキャッシュに保存しません(マニフェスト ファイル自体に明示的にリストされている場合を除きます)。つまり、ユーザーが移動したページで manifest が含まれている場合、そのページは暗黙的にアプリ キャッシュに追加されます。そのため、マニフェストにすべてのページを記載する必要はありません。ページがマニフェストを指している場合、このページがキャッシュに保存されるのを防ぐ方法はありません。

Chrome で about://://appcache-internals/ にアクセスすると、アプリケーション キャッシュによって管理されている URL を確認できます。ここで、キャッシュを消去したり、エントリを確認したりできます。Firefox には同様のデベロッパー ツールがあります。

manifest 属性には、絶対 URL または相対パスを指定できますが、絶対 URL はウェブ アプリケーションと同じオリジンにする必要があります。マニフェスト ファイルには任意のファイル拡張子を設定できますが、正しい MIME タイプで提供する必要があります(以下を参照)。

<html manifest="http://www.example.com/example.mf">
  ...
</html>

マニフェスト ファイルは、mime-type text/cache-manifest で配信する必要があります。ウェブサーバーまたは .htaccess 構成にカスタム ファイルタイプを追加することが必要になる場合があります。

たとえば、Apache でこの MIME タイプを提供する場合は、構成ファイルに次の行を追加します。

AddType text/cache-manifest .appcache

また、Google App Engine の app.yaml ファイルの場合は以下のようになります。

- url: /mystaticdir/(.*\.appcache)
  static_files: mystaticdir/\1
  mime_type: text/cache-manifest
  upload: mystaticdir/(.*\.appcache)

この要件はしばらく前に仕様から削除され、最新バージョンの Chrome、Safari、Firefox では不要になりましたが、古いブラウザと IE11 で動作させるには mime-type が必要です。

マニフェスト ファイルの構造

マニフェストは、html 要素の manifest 属性を介してリンクする別のファイルです。簡単なマニフェストは次のようになります。

CACHE MANIFEST
index.html
stylesheet.css
images/logo.png
scripts/main.js
http://cdn.example.com/scripts/main.js

この例では、このマニフェスト ファイルを指定するページに 4 つのファイルをキャッシュに保存します。

次の点に注意してください。

  • CACHE MANIFEST 文字列は最初の行で、必須です。
  • 別のドメインのファイルを使用できます
  • 一部のブラウザでは、アプリで使用できるストレージ割り当ての量に制限が設けられています。たとえば、Chrome では、AppCache は他のオフライン API が共有できる一時ストレージの共有プールを使用します。Chrome ウェブストア向けのアプリを作成する場合は、unlimitedStorage を使用することでこの制限を回避できます。
  • マニフェスト自体が 404 または 410 を返した場合、キャッシュは削除されます。
  • マニフェストまたは指定されたリソースのダウンロードに失敗すると、キャッシュの更新プロセス全体が失敗します。エラーが発生した場合、ブラウザは古いアプリケーション キャッシュを引き続き使用します。

より複雑な例を見てみましょう。

CACHE MANIFEST
# 2010-06-18:v2

# Explicitly cached 'master entries'.
CACHE:
/favicon.ico
index.html
stylesheet.css
images/logo.png
scripts/main.js

# Resources that require the user to be online.
NETWORK:
*

# static.html will be served if main.py is inaccessible
# offline.jpg will be served in place of all images in images/large/
# offline.html will be served in place of all other .html files
FALLBACK:
/main.py /static.html
images/large/ images/offline.jpg

「#」で始まる行はコメント行ですが、別の目的で使用することもできます。アプリケーションのキャッシュは、マニフェスト ファイルが変更された場合にのみ更新されます。たとえば、画像リソースを編集したり、JavaScript 関数を変更したりしても、それらの変更は再キャッシュされません。キャッシュに保存されたファイルを更新するようブラウザに通知するには、マニフェスト ファイル自体を変更する必要があります

常に更新されるタイムスタンプやランダムな文字列を使用して、毎回強制的に更新しないようにしてください。マニフェストは、更新中に 2 回チェックされます。1 回は開始時に、もう 1 回はキャッシュに保存されているすべてのファイルが更新された後にチェックされます。更新中にマニフェストが変更された場合、ブラウザが一部のファイルをあるバージョンから、他のファイルを別のバージョンから取得したため、キャッシュが適用されず、後で再試行される可能性があります。

キャッシュは更新されますが、更新は現在のバージョンのキャッシュからページが読み込まれた後に行われるため、ページが更新されるまでブラウザはこれらのファイルを使用しません。

マニフェストには、CACHENETWORKFALLBACK の 3 つのセクションを含めることができます。

CACHE:
このセクションは、エントリのデフォルトのセクションです。このヘッダーの下(または CACHE MANIFEST の直後)にリストされているファイルは、初回ダウンロード後に明示的にキャッシュに保存されます。NETWORK:
このセクションにリストされているファイルは、キャッシュにない場合はネットワークから取得される場合があります。それ以外の場合は、ユーザーがオンラインであってもネットワークは使用されません。ここで、特定の URL をホワイトリストに登録できます。または、すべての URL を許可する「」を指定することもできます。ほとんどのサイトでは「」が必要です。 FALLBACK:
リソースにアクセスできない場合の代替ページを指定するオプションのセクション。最初の URI はリソースで、2 番目の URI はネットワーク リクエストが失敗した場合やエラーが発生した場合に使用されるフォールバックです。どちらの URI も、マニフェスト ファイルと同じ生成元からのものである必要があります。特定の URL だけでなく、URL の接頭辞もキャプチャできます。「images/large/」は、「images/large/whatever/img.jpg」などの URL からのエラーをキャプチャします。

次のマニフェストは、ユーザーがオフラインでサイトのルートにアクセスしようとしたときに表示される「キャッチオール」ページ(offline.html)を定義します。また、他のすべてのリソース(リモート サイト上のリソースなど)にはインターネット接続が必要であることを宣言します。

CACHE MANIFEST
# 2010-06-18:v3

# Explicitly cached entries
index.html
css/style.css

# offline.html will be displayed if the user is offline
FALLBACK:
/ /offline.html

# All other resources (e.g. sites) require the user to be online.
NETWORK:
*

# Additional resources to cache
CACHE:
images/logo1.png
images/logo2.png
images/logo3.png

キャッシュの更新

アプリケーションがオフラインになると、次のいずれかが発生するまでキャッシュされたままになります。

  1. ユーザーがサイトのブラウザのデータ ストレージを消去した場合。
  2. マニフェスト ファイルが変更されます。注: マニフェストに記載されているファイルを更新しても、ブラウザがそのリソースを再キャッシュするわけではありません。マニフェスト ファイル自体を変更する必要があります。

キャッシュ ステータス

window.applicationCache オブジェクトは、ブラウザのアプリキャッシュへのプログラムによるアクセスです。status プロパティは、キャッシュの現在の状態を確認するのに役立ちます。

var appCache = window.applicationCache;

switch (appCache.status) {
case appCache.UNCACHED: // UNCACHED == 0
return 'UNCACHED';
break;
case appCache.IDLE: // IDLE == 1
return 'IDLE';
break;
case appCache.CHECKING: // CHECKING == 2
return 'CHECKING';
break;
case appCache.DOWNLOADING: // DOWNLOADING == 3
return 'DOWNLOADING';
break;
case appCache.UPDATEREADY:  // UPDATEREADY == 4
return 'UPDATEREADY';
break;
case appCache.OBSOLETE: // OBSOLETE == 5
return 'OBSOLETE';
break;
default:
return 'UKNOWN CACHE STATUS';
break;
};

マニフェストの更新をプログラムで確認するには、まず applicationCache.update() を呼び出します。これにより、ユーザーのキャッシュの更新が試行されます(マニフェスト ファイルが変更されている必要があります)。最後に、applicationCache.statusUPDATEREADY 状態になると、applicationCache.swapCache() を呼び出すと、古いキャッシュが新しいキャッシュにスワップされます。

var appCache = window.applicationCache;

appCache.update(); // Attempt to update the user's cache.

...

if (appCache.status == window.applicationCache.UPDATEREADY) {
appCache.swapCache();  // The fetch was successful, swap in the new cache.
}

幸い、この作業は自動化できます。ユーザーをサイトの最新バージョンに更新するには、ページ読み込み時に updateready イベントをモニタリングするリスナーを設定します。

// Check if a new cache is available on page load.
window.addEventListener('load', function(e) {

window.applicationCache.addEventListener('updateready', function(e) {
if (window.applicationCache.status == window.applicationCache.UPDATEREADY) {
    // Browser downloaded a new app cache.
    if (confirm('A new version of this site is available. Load it?')) {
    window.location.reload();
    }
} else {
    // Manifest didn't changed. Nothing new to server.
}
}, false);

}, false);

AppCache イベント

予想どおり、キャッシュの状態をモニタリングするための追加イベントが公開されます。ブラウザは、ダウンロードの進行状況、アプリ キャッシュの更新、エラー状態などのイベントを発生させます。以下のスニペットでは、各タイプのキャッシュ イベントに対してイベント リスナーを設定しています。

function handleCacheEvent(e) {
//...
}

function handleCacheError(e) {
alert('Error: Cache failed to update!');
};

// Fired after the first cache of the manifest.
appCache.addEventListener('cached', handleCacheEvent, false);

// Checking for an update. Always the first event fired in the sequence.
appCache.addEventListener('checking', handleCacheEvent, false);

// An update was found. The browser is fetching resources.
appCache.addEventListener('downloading', handleCacheEvent, false);

// The manifest returns 404 or 410, the download failed,
// or the manifest changed while the download was in progress.
appCache.addEventListener('error', handleCacheError, false);

// Fired after the first download of the manifest.
appCache.addEventListener('noupdate', handleCacheEvent, false);

// Fired if the manifest file returns a 404 or 410.
// This results in the application cache being deleted.
appCache.addEventListener('obsolete', handleCacheEvent, false);

// Fired for each resource listed in the manifest as it is being fetched.
appCache.addEventListener('progress', handleCacheEvent, false);

// Fired when the manifest resources have been newly redownloaded.
appCache.addEventListener('updateready', handleCacheEvent, false);

マニフェスト ファイルまたはそれに指定されたリソースのダウンロードに失敗すると、更新全体が失敗します。このような障害が発生しても、ブラウザは古いアプリケーション キャッシュを引き続き使用します。

参照