애플리케이션 캐시 사용에 대한 초보자 가이드

소개

웹 기반 애플리케이션에 오프라인으로 액세스할 수 있는 것이 점점 더 중요해지고 있습니다. 예, 모든 브라우저는 오랜 기간 동안 페이지와 리소스를 캐시하도록 요청할 수 있지만, 브라우저는 다른 항목을 위한 공간을 확보하기 위해 언제든지 캐시에서 개별 항목을 삭제할 수 있습니다. HTML5는 ApplicationCache 인터페이스를 통해 오프라인으로 사용할 수 있는 몇 가지 문제를 해결했습니다. 캐시 인터페이스를 사용하면 애플리케이션에 다음과 같은 세 가지 이점이 있습니다.

  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 유형 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가 공유할 수 있는 TEMPORARY 저장소의 공유 풀을 사용합니다. 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

'#'로 시작하는 행은 주석 행이지만 다른 용도로 사용할 수도 있습니다. 애플리케이션의 캐시는 매니페스트 파일이 변경될 때만 업데이트됩니다. 예를 들어 이미지 리소스를 수정하거나 자바스크립트 함수를 변경해도 이러한 변경사항은 다시 캐시되지 않습니다. 브라우저가 캐시된 파일을 새로고침하도록 매니페스트 파일 자체를 수정해야 합니다.

지속적으로 업데이트되는 타임스탬프나 임의의 문자열을 사용하여 매번 강제 업데이트를 하지 마세요. 매니페스트는 업데이트 시 두 번, 즉 시작할 때 한 번, 캐시된 모든 파일이 업데이트된 후에 검사됩니다. 업데이트 중에 매니페스트가 변경되었다면 브라우저가 한 버전에서 일부 파일을 가져오고 다른 버전에서 다른 파일을 가져왔으므로 캐시를 적용하고 나중에 다시 시도할 수 있습니다.

캐시가 업데이트되더라도 페이지는 현재 버전의 캐시에서 페이지가 로드된 후에 업데이트가 이루어지기 때문에 브라우저는 페이지를 새로 고칠 때까지 이러한 파일을 사용하지 않습니다.

매니페스트에는 CACHE, NETWORK, FALLBACK라는 세 가지 개별 섹션이 있을 수 있습니다.

CACHE:
항목의 기본 섹션입니다. 이 헤더 아래 (또는 CACHE MANIFEST 바로 뒤에) 나열된 파일은 처음 다운로드한 후 명시적으로 캐시됩니다. NETWORK:
이 섹션에 나열된 파일은 캐시에 없는 경우 네트워크에서 가져온 파일일 수 있으며, 캐시에 없는 경우 사용자가 온라인 상태여도 네트워크가 사용되지 않습니다. 여기에서 특정 URL 또는 모든 URL을 허용하는 ''을(를) 허용 목록에 추가할 수 있습니다. 대부분의 사이트에는 ''이(가) 필요합니다. FALLBACK:
리소스에 액세스할 수 없는 경우 대체 페이지를 지정하는 섹션(선택사항)입니다. 첫 번째 URI는 리소스이고, 두 번째 URI는 네트워크 요청이 실패하거나 오류일 때 사용되는 대체 URI입니다. 두 URI 모두 매니페스트 파일과 출처가 동일해야 합니다. 특정 URL뿐만 아니라 URL 프리픽스도 캡처할 수 있습니다. 'images/large/'는 'images/large/whatever/img.jpg'와 같은 URL에서 실패를 캡처합니다.

다음 매니페스트는 사용자가 오프라인일 때 사이트의 루트에 액세스하려고 할 때 표시될 'catch-all' 페이지 (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);

매니페스트 파일이나 파일에 지정된 리소스를 다운로드하지 못하면 전체 업데이트가 실패합니다. 이러한 오류가 발생하더라도 브라우저는 기존 애플리케이션 캐시를 계속 사용합니다.

참조