소개
웹 기반 애플리케이션에 오프라인 액세스 기능이 제공되는 것이 점점 더 중요해지고 있습니다. 예. 모든 브라우저는 지시된 경우 페이지와 리소스를 장기간 캐시할 수 있지만, 브라우저는 언제든지 다른 항목을 위한 공간을 확보하기 위해 개별 항목을 캐시에서 삭제할 수 있습니다. HTML5는 ApplicationCache 인터페이스를 사용하여 오프라인 상태일 때의 불편함을 해결합니다. 캐시 인터페이스를 사용하면 애플리케이션에 다음과 같은 세 가지 이점이 있습니다.
- 오프라인 탐색 - 사용자가 오프라인 상태에서 전체 사이트를 탐색할 수 있습니다.
- 속도 - 리소스가 네트워크를 거치지 않고 디스크에서 바로 가져옵니다.
- 복원력 - 누군가가 실수로 모든 것을 망가뜨리는 경우와 같이 '유지관리'로 인해 사이트가 다운되면 사용자는 오프라인 환경을 이용하게 됩니다.
애플리케이션 캐시(또는 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 유형이 필요합니다.
매니페스트 파일의 구조
매니페스트는 html 요소의 매니페스트 속성을 통해 연결되는 별도의 파일입니다. 간단한 매니페스트는 다음과 같습니다.
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 함수를 변경해도 이러한 변경사항은 다시 캐시되지 않습니다. 브라우저에 캐시된 파일을 새로고침하도록 알리려면 매니페스트 파일 자체를 수정해야 합니다.
지속적으로 업데이트되는 타임스탬프나 임의의 문자열을 사용하여 매번 강제 업데이트를 하지 않도록 합니다. 매니페스트는 업데이트 중에 두 번 확인됩니다. 시작 시 한 번, 모든 캐시된 파일이 업데이트된 후 한 번 확인됩니다. 업데이트 중에 매니페스트가 변경된 경우 브라우저가 한 버전에서 일부 파일을 가져오고 다른 버전에서 다른 파일을 가져왔을 수 있으므로 캐시가 적용되지 않고 나중에 다시 시도합니다.
캐시가 업데이트되더라도 페이지는 페이지가 새로고침될 때까지 브라우저에서 해당 파일을 사용하지 않습니다. 이는 캐시의 현재 버전에서 페이지가 로드된 후에 업데이트가 이루어지기 때문입니다.
매니페스트에는 CACHE
, NETWORK
, FALLBACK
라는 세 가지 섹션이 있을 수 있습니다.
CACHE:
- 항목의 기본 섹션입니다. 이 헤더 아래에 나열된 파일(또는
CACHE MANIFEST
바로 뒤)은 처음 다운로드된 후 명시적으로 캐시됩니다.NETWORK:
- 이 섹션에 나열된 파일이 캐시에 없는 경우 네트워크에서 가져올 수 있습니다. 그렇지 않으면 사용자가 온라인 상태이더라도 네트워크가 사용되지 않습니다. 여기에서 특정 URL을 허용 목록에 추가하거나 모든 URL을 허용하는 ''을 입력할 수 있습니다. 대부분의 사이트에는 ''이 필요합니다.
FALLBACK:
- 리소스에 액세스할 수 없는 경우 대체 페이지를 지정하는 선택적 섹션입니다. 첫 번째 URI는 리소스이고 두 번째 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 사양
- Application Cache is a douchebag: AppCache의 문제점과 함정을 다룹니다.