Search
Duplicate
💵

[Next.js] Service worker caching

간단소개
service-worker caching을 구현해보자
팔만코딩경 컨트리뷰터
ContributorNotionAccount
주제 / 분류
Next.js
Javascript
Scrap
태그
9 more properties
KakaoMap API는 3,000,000회의 월간 호출 제한이 있다.
서비스를 구현하다보니 지도 생성 외에도 Search, Geocoder등 다양한 기능들을 활용하다보니 사용자 1명당 1회 사용시 호출 최대치가 150 - 200회 정도가 나왔다.
동료 개발자분이(@JaeSeoKim) Search의 경우 Service worker를 활용한 caching을 도입해보는 것을 추천해주셔서 바로 시도해보았다. 이미 PWA를 위해 service worker를 등록해 두었기 때문에 어렵지 않게 기능을 구현해 볼 수 있었다.
Geocoder를 사용하는 부분은 throttle, debounce등을 활용해서 호출 횟수를 제한했다.

Service worker caching

1. Service worker 등록하기

Next.js 어플리케이션에 Service worker를 등록하는것은 어렵지 않다. Service worker는 브라우저에 종속적이기 때문에 useEffect 훅으로 감싸준 후 등록가능한 기기에 대해서 sw.js 파일(파일이름은 원하는 이름으로 작성)을 등록해주면 된다.
useEffect(() => { if ('serviceWorker' in navigator) { const registInit = async () => { const registration = await navigator.serviceWorker.register('/sw.js'); registration.waiting?.postMessage('SKIP_WAITING'); }; registInit(); } }, []);
TypeScript
복사
정상적으로 등록되면 아래와 같이 개발자 도구에서 확인할 수 있다.

2. Service worker caching 패턴

Service worker caching을 사용하기위한 몇가지 패턴이 있다. 상황에 맞게 필요한 패턴으로 개발을 진행하면 된다.
내가 필요한 패턴은 Cache, falling back to Network였다. 간단히 설명하면 Cache에 먼저 요청하고, 없으면 Network요청을 보내는 방식이다.

3. Service worker 작성하기

위에 나온 방식을 활용해서 코드를 작성해보자.
1.
fetch 이벤트 리스너 등록
2.
Cache에 해당 request에 대한 내용이 등록되어있는지 확인
a.
있다면 response return
b.
없으면 fetch api를 활용해 network request 전송
받아온 응답을 캐시에 저장 (max-age를 원하는 시간으로 설정)
response return
self.addEventListener('fetch', (event) => { event.respondWith( caches.open('cache-v1').then((cache) => { return cache.match(event.request).then((response) => { if (response) { console.log('cache hit!!'); return response; } else { console.log('cache miss...'); return fetch(event.request).then((response) => { // 캐시 메타데이터 설정 var cacheHeaders = new Headers(response.headers); cacheHeaders.append('Cache-Control', 'max-age=604800'); var cachedResponse = new Response(response.body, { status: response.status, statusText: response.statusText, headers: cacheHeaders, }); cache.put(event.request, cachedResponse); return response; }); } }); }) ); });
TypeScript
복사
KakaoMap API에 등록된 주소정보가 크게 변하지 않을 것 같아서 1주일 정도 캐싱해두기로 하였다.

4. 특정 도메인에 대해서만 적용하기

모든 네트워크 요청에 대해 동일한 Caching 패턴을 적용할 수 없기 때문에 도메인을 기준으로 묶어주었다.
self.addEventListener('fetch', (event) => { // 특정 도메인에서 요청한 리소스만 캐싱 if ( event.request.url.startsWith('http://dapi.kakao.com/v2/local/search/') ) { // event.respondWith( ... } else { // do something... } });
TypeScript
복사

5. 테스트하기

이제 정상적으로 작동하는지 테스트해보자. 아래 사진은 처음 “커피빈”이라는 검색을 한 상황이다. 오른쪽에 cache miss라는 콘솔이 출력되는 것을 볼 수 있다.
아래는 동일한 텍스트를 여러번 입력하는 경우이다. 오른쪽 콘솔을 보면 cache hit이 지속적으로 출력되는 것을 확인할 수 있다.

아직은..

KakaoMap API의 요청 URL은 아래처럼 생겼다.
http://dapi.kakao.com/v2/local/search/keyword.json?query=’querystring’&x=x좌표&y=y좌표&page=1&size=15
그래서 동일한 좌표에서 검색하는게 아니라면 같은 내용을 검색하더라도 Caching된 데이터를 가져오지 못한다. 추후 업데이트를 통해 반경 1km내의 Caching된 데이터가 있으면 해당 데이터에 대한 response를 return하는 로직을 추가하려고 한다.

Reference