Cache API를 사용하여 애플리케이션 데이터를 오프라인으로 사용할 수 있도록 하는 방법을 알아봅니다.
Cache API는 네트워크 요청과 해당 응답을 저장하고 검색하는 시스템입니다. 이는 애플리케이션을 실행하는 과정에서 생성된 일반 요청 및 응답일 수도 있고 나중에 사용할 데이터를 저장하기 위한 목적으로만 생성될 수도 있습니다.
Cache API는 서비스 워커가 네트워크 속도 또는 가용성에 관계없이 빠른 응답을 제공할 수 있도록 네트워크 요청을 캐시할 수 있도록 하기 위해 만들어졌습니다. 그러나 이 API는 일반적인 저장소 메커니즘으로도 사용할 수 있습니다.
어느 지역에서 제공되나요?
Cache API는 모든 최신 브라우저에서 사용할 수 있습니다. 전역 caches
속성을 통해 노출되므로 간단한 기능 감지로 API의 존재를 테스트할 수 있습니다.
const cacheAvailable = 'caches' in self;
Cache API는 창, iframe, 워커 또는 서비스 워커에서 액세스할 수 있습니다.
저장할 수 있는 항목
캐시에는 각각 HTTP 요청과 응답을 나타내는 Request
및 Response
객체 쌍만 저장됩니다. 그러나 요청과 응답에는 HTTP를 통해 전송할 수 있는 모든 종류의 데이터가 포함될 수 있습니다.
얼마나 저장할 수 있나요?
간단히 말해 매우 많습니다. 최소 수백 메가바이트에서 수백 기가바이트 이상일 수 있습니다. 브라우저 구현은 다양하지만 사용 가능한 저장용량은 일반적으로 기기에서 사용 가능한 저장용량을 기준으로 합니다.
캐시 만들기 및 열기
캐시를 열려면 caches.open(name)
메서드를 사용하여 캐시 이름을 단일 매개변수로 전달합니다. 이름이 지정된 캐시가 없으면 캐시가 생성됩니다. 이 메서드는 Cache
객체로 확인되는 Promise
를 반환합니다.
const cache = await caches.open('my-cache');
// do something with cache...
캐시에 추가
캐시에 항목을 추가하는 방법에는 add
, addAll
, put
의 세 가지가 있습니다.
세 메서드 모두 Promise
를 반환합니다.
cache.add
첫 번째는 cache.add()
입니다. Request
또는 URL (string
) 매개변수 하나를 사용합니다. 네트워크에 요청을 보내고 응답을 캐시에 저장합니다. 가져오기에 실패하거나 응답의 상태 코드가 200 범위에 있지 않으면 아무것도 저장되지 않고 Promise
가 거부됩니다. CORS 모드가 아닌 교차 출처 요청은 0
의 status
를 반환하므로 저장할 수 없습니다. 이러한 요청은 put
로만 저장할 수 있습니다.
// Retreive data.json from the server and store the response.
cache.add(new Request('/data.json'));
// Retreive data.json from the server and store the response.
cache.add('/data.json');
cache.addAll
다음은 cache.addAll()
입니다. add()
와 비슷하게 작동하지만 Request
객체 또는 URL (string
) 배열을 사용합니다. 이는 개별 요청마다 cache.add
를 호출하는 것과 유사하게 작동하지만, 단일 요청이 캐시되지 않으면 Promise
가 거부된다는 점을 제외하고는 동일합니다.
const urls = ['/weather/today.json', '/weather/tomorrow.json'];
cache.addAll(urls);
이 경우 새 항목이 일치하는 기존 항목을 덮어씁니다. 여기서는 검색 섹션에 설명된 것과 동일한 일치 규칙을 사용합니다.
cache.put
마지막으로 cache.put()
가 있습니다. 이 cache.put()
를 사용하면 네트워크의 응답을 저장하거나 자체 Response
를 만들고 저장할 수 있습니다. 두 개의 매개변수를 사용합니다. 첫 번째는 Request
객체 또는 URL (string
)일 수 있습니다. 두 번째는 네트워크에서 가져오거나 코드에서 생성한 Response
여야 합니다.
// Retrieve data.json from the server and store the response.
cache.put('/data.json');
// Create a new entry for test.json and store the newly created response.
cache.put('/test.json', new Response('{"foo": "bar"}'));
// Retrieve data.json from the 3rd party site and store the response.
cache.put('https://example.com/data.json');
put()
메서드는 add()
또는 addAll()
보다 관대한 메서드이며, CORS가 아닌 응답이나 응답의 상태 코드가 200 범위에 있지 않은 다른 응답을 저장할 수 있습니다. 동일한 요청에 대한 이전 응답을 덮어씁니다.
요청 객체 만들기
저장되는 항목의 URL을 사용하여 Request
객체를 만듭니다.
const request = new Request('/my-data-store/item-id');
Response 객체 작업
Response
객체 생성자는 Blob
, ArrayBuffer
, FormData
객체, 문자열을 비롯한 다양한 유형의 데이터를 허용합니다.
const imageBlob = new Blob([data], {type: 'image/jpeg'});
const imageResponse = new Response(imageBlob);
const stringResponse = new Response('Hello world');
적절한 헤더를 설정하여 Response
의 MIME 유형을 설정할 수 있습니다.
const options = {
headers: {
'Content-Type': 'application/json'
}
}
const jsonResponse = new Response('{}', options);
Response
를 검색했고 본문에 액세스하려는 경우 사용할 수 있는 여러 도우미 메서드가 있습니다. 각 메서드는 다른 유형의 값으로 확인되는 Promise
를 반환합니다.
메서드 | 설명 |
---|---|
arrayBuffer |
바이트로 직렬화된 본문이 포함된 ArrayBuffer 를 반환합니다.
|
blob |
Blob 를 반환합니다. Response 가 Blob 로 생성된 경우 이 새 Blob 의 유형은 동일합니다. 그렇지 않으면 Response 의 Content-Type 가 사용됩니다.
|
text |
본문의 바이트를 UTF-8 인코딩된 문자열로 해석합니다. |
json |
본문의 바이트를 UTF-8 인코딩된 문자열로 해석한 후 JSON으로 파싱하려고 시도합니다. 결과 객체를 반환하거나 문자열을 JSON으로 파싱할 수 없는 경우 TypeError 을 발생시킵니다.
|
formData |
본문의 바이트를 multipart/form-data 또는 application/x-www-form-urlencoded 로 인코딩된 HTML 양식으로 해석합니다. FormData 객체를 반환하거나 데이터를 파싱할 수 없는 경우 TypeError 을 발생시킵니다.
|
body |
본문 데이터의 ReadableStream을 반환합니다. |
예를 들면 다음과 같습니다.
const response = new Response('Hello world');
const buffer = await response.arrayBuffer();
console.log(new Uint8Array(buffer));
// Uint8Array(11) [72, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100]
캐시에서 검색
캐시에서 항목을 찾으려면 match
메서드를 사용하면 됩니다.
const response = await cache.match(request);
console.log(request, response);
request
가 문자열인 경우 브라우저는 new Request(request)
를 호출하여 request
를 Request
로 변환합니다. 이 함수는 일치하는 항목이 발견되면 Response
로 확인되는 Promise
를 반환하고 그렇지 않으면 undefined
를 반환합니다.
두 개의 Requests
가 일치하는지 확인하기 위해 브라우저는 URL 외에도 다른 항목을 사용합니다. 두 요청의 쿼리 문자열, Vary
헤더 또는 HTTP 메서드 (GET
, POST
, PUT
등)가 서로 다른 경우 서로 다른 요청으로 간주됩니다.
옵션 객체를 두 번째 매개변수로 전달하여 이러한 항목의 일부 또는 전부를 무시할 수 있습니다.
const options = {
ignoreSearch: true,
ignoreMethod: true,
ignoreVary: true
};
const response = await cache.match(request, options);
// do something with the response
캐시된 요청이 두 개 이상 일치하는 경우 먼저 생성된 요청이 반환됩니다. 일치하는 응답을 모두 검색하려면 cache.matchAll()
를 사용하면 됩니다.
const options = {
ignoreSearch: true,
ignoreMethod: true,
ignoreVary: true
};
const responses = await cache.matchAll(request, options);
console.log(`There are ${responses.length} matching responses.`);
단축키로 각 캐시의 cache.match()
를 호출하는 대신 caches.match()
를 사용하여 모든 캐시를 한 번에 검색할 수 있습니다.
검색 중
Cache API는 Response
객체와 일치하는 항목을 제외하고 요청이나 응답을 검색하는 방법을 제공하지 않습니다. 하지만 필터링을 사용하거나 색인을 만들어 자체 검색을 구현할 수 있습니다.
필터링
자체 검색을 구현하는 한 가지 방법은 모든 항목을 반복하고 원하는 항목으로 필터링하는 것입니다. .png
로 끝나는 URL이 있는 모든 항목을 찾으려 한다고 가정해 보겠습니다.
async function findImages() {
// Get a list of all of the caches for this origin
const cacheNames = await caches.keys();
const result = [];
for (const name of cacheNames) {
// Open the cache
const cache = await caches.open(name);
// Get a list of entries. Each item is a Request object
for (const request of await cache.keys()) {
// If the request URL matches, add the response to the result
if (request.url.endsWith('.png')) {
result.push(await cache.match(request));
}
}
}
return result;
}
이렇게 하면 Request
및 Response
객체의 속성을 사용하여 항목을 필터링할 수 있습니다. 대규모 데이터 세트를 검색하는 경우 속도가 느려집니다.
색인 만들기
자체 검색을 구현하는 다른 방법은 검색할 수 있는 항목의 별도 색인을 유지하고 색인을 IndexedDB에 저장하는 것입니다. 이는 IndexedDB가 설계된 작업 유형이므로 항목 수가 많을 때 성능이 훨씬 우수합니다.
검색 가능한 속성과 함께 Request
의 URL을 저장하면 검색 후 올바른 캐시 항목을 쉽게 검색할 수 있습니다.
항목 삭제
캐시에서 항목을 삭제하려면 다음 단계를 따르세요.
cache.delete(request);
여기서 요청은 Request
또는 URL 문자열일 수 있습니다. 이 메서드는 cache.match
와 동일한 옵션 객체도 사용합니다. 따라서 동일한 URL에 대해 여러 개의 Request
/Response
쌍을 삭제할 수 있습니다.
cache.delete('/example/file.txt', {ignoreVary: true, ignoreSearch: true});
캐시 삭제
캐시를 삭제하려면 caches.delete(name)
를 호출합니다. 이 함수는 캐시가 존재하고 삭제된 경우 true
로 확인되는 Promise
을 반환하고 그렇지 않은 경우에는 false
을 반환합니다.
감사합니다.
이 도움말의 원본 버전을 작성하고 WebFundamentals에 처음 게시한 맷 스케일스님께 감사드립니다.