はじめに
ウェブベースのアプリケーションにオフラインでアクセス可能であることは、ますます重要になっています。はい。どのブラウザでも、ページとリソースを長期間キャッシュに保存できます。ただし、キャッシュから個々のアイテムをいつでもキャッシュから外して、他のスペースを確保できます。HTML5 では、ApplicationCache インターフェースにより、オフラインの煩わしさの一部に対処しています。キャッシュ インターフェースを使用すると、アプリケーションに 3 つの利点があります。
- オフライン ブラウジング - オフラインのときでもサイト全体にアクセスできます
- 速度 - リソースはディスクから直接取得されるため、ネットワークを経由する必要がありません。
- 復元力 - 「メンテナンス」のためにサイトがダウンした場合(誰かが誤ってすべてを壊した場合など)、ユーザーはオフライン エクスペリエンスを提供します
デベロッパーはアプリケーション キャッシュ(AppCache)を使用することで、どのファイルをブラウザでキャッシュに保存してオフライン ユーザーが利用できるようにするかを指定できます。ユーザーがオフラインのときに更新ボタンを押しても、アプリは読み込まれて正常に動作します。
キャッシュ マニフェスト ファイル
キャッシュ マニフェスト ファイルは、ブラウザがオフライン アクセスのためにキャッシュに保存する必要があるリソースをリストしたシンプルなテキスト ファイルです。
マニフェスト ファイルの参照
アプリのアプリ キャッシュを有効にするには、ドキュメントの html
タグにマニフェスト属性を追加します。
<html manifest="example.appcache">
...
</html>
manifest
属性は、キャッシュに保存するウェブ アプリケーションのすべてのページに含める必要があります。manifest
属性が含まれていない場合、ブラウザはページをキャッシュに保存しません(マニフェスト ファイル自体に明示的に指定されている場合を除く)。つまり、manifest
を含むユーザーが移動したページは、暗黙的にアプリ キャッシュに追加されます。したがって、マニフェストにすべてのページを記述する必要はありません。ページがマニフェストを参照している場合、そのページがキャッシュに保存されるのを防ぐ方法はありません。
アプリケーション キャッシュによって制御されている URL は、Chrome で about://appcache-internals/ にアクセスすると確認できます。ここでキャッシュを消去し、エントリを表示できます。Firefox にも同様のデベロッパー ツールがあります。
manifest
属性では、絶対 URL または相対パスを指定できますが、絶対 URL は、ウェブ アプリケーションと同じオリジンにする必要があります。マニフェスト ファイルは任意のファイル拡張子にできますが、適切な MIME タイプで提供する必要があります(下記参照)。
<html manifest="http://www.example.com/example.mf">
...
</html>
マニフェスト ファイルは MIME タイプ 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 タイプが必要になります。
マニフェスト ファイルの構造
マニフェストは、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 回目は起動時にチェックされ、2 回目はキャッシュされたすべてのファイルが更新された後です。アップデート中にマニフェストが変更された場合、ブラウザがあるバージョンから一部のファイルを取得し、別のバージョンから他のファイルを取得している可能性があります。この場合、キャッシュは適用されず、後で再試行されます。
キャッシュは更新されますが、更新はページが現在のバージョンのキャッシュから読み込まれた後に行われるため、ページが更新されるまでブラウザはこれらのファイルを使用しません。
マニフェストには、CACHE
、NETWORK
、FALLBACK
の 3 つのセクションがあります。
CACHE:
- これはエントリのデフォルト セクションです。このヘッダーの下(または
CACHE MANIFEST
の直後)にリストされているファイルは、初めてダウンロードされた後、明示的にキャッシュに保存されます。NETWORK:
- このセクションに記載されているファイルは、キャッシュにない場合はネットワークから取得された可能性があります。それ以外の場合は、ユーザーがオンラインであってもネットワークは使用されません。ここで特定の URL を許可リストに登録することも、単に「」を指定してすべての URL を許可することもできます。ほとんどのサイトでは「」が必要です。
FALLBACK:
- リソースにアクセスできない場合の代替ページを指定するオプションのセクション。1 つ目の 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
キャッシュの更新
アプリケーションがオフラインになると、次のいずれかが発生するまでキャッシュされたままになります。
- ユーザーがブラウザのデータ ストレージを消去した。
- マニフェスト ファイルが変更された。注: マニフェストにリストされているファイルを更新しても、ブラウザがそのリソースを再度キャッシュに保存するわけではありません。マニフェスト ファイル自体を変更する必要があります。
キャッシュ ステータス
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.status
が UPDATEREADY
状態のときに 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);
マニフェスト ファイルまたはマニフェスト ファイルで指定されているリソースのダウンロードが失敗すると、アップデート全体が失敗します。このような障害が発生した場合、ブラウザでは引き続き古いアプリケーション キャッシュが使用されます。
参照
- ApplicationCache API 仕様
- アプリケーション キャッシュは大道具で、AppCache の問題点や問題をカバーしています。