보이지 않는 레이어: HTTP 캐싱 마스터링 (Part 2)
Source: Dev.to
데이터베이스의 데이터를 업데이트했는데 사용자는 여전히 오래된 버전을 보고 있다며 브라우저를 급히 새로 고침한 적이 있다면, 여러분은 HTTP 캐시와 마주한 것입니다.
fetch('/api/user')를 호출하면 브라우저가 바로 인터넷에 요청을 보내지는 않습니다. 대신 다음과 같은 엄격한 체크리스트를 실행합니다:
- Memory/Disk Check – 로컬에 이 복사본이 있나요?
- Expiration Check – 있다면,
max-age를 기준으로 아직 신선한가요? - Short Circuit – 신선하다면, 브라우저는 데이터를 즉시 반환하고 서버와는 전혀 통신하지 않습니다.
이러한 단계들은 Cache‑Control 헤더에 의해 제어됩니다.
캐시 제어
웹 성능을 위한 가장 중요한 헤더입니다. 브라우저에게 정확히 어떻게 동작해야 하는지 알려줍니다.
max-age (타이머)
Cache-Control: max-age=3600
데이터는 1시간(3600초) 동안 신선합니다. 브라우저는 그 시간이 만료될 때까지 서버에 다시 요청하지 않습니다.
함정: 중요한 버그 수정을 5분 후에 배포하면, 캐시된 버전을 가진 사용자는 추가로 55분 동안 이를 보지 못합니다.
no-cache vs no-store (큰 혼란)
| Directive | Meaning | Typical Use |
|---|---|---|
no-store | 이 응답을 절대 저장하지 않음. | 민감한 데이터(예: 은행 정보) 또는 매밀리초마다 변경되는 데이터. |
no-cache | 저장하되 사용하기 전에 서버와 재검증함. | 매 요청마다 최신 버전이 필요할 때. |
참고:
no-cache는 브라우저가 매 요청마다 서버에 “이 버전이 아직 유효한가요?”라고 물어보도록 강제합니다.
참조: MDN Web Docs – Cache‑Control
ETags 및 Last‑Modified (304 Not Modified)
대용량 리소스(예: 5,000개의 제품 목록이 포함된 2 MB 파일)를 다룰 때는 매번 전체 파일을 다운로드하고 싶지 않습니다.
- 첫 번째 요청: 서버가 데이터와 함께
ETag(고유 해시/지문)를 전송합니다. - 후속 요청: 브라우저가
ETag를If-None-Match에 담아 다시 보냅니다. - 서버 응답: 해시가 일치하면 304 Not Modified를 반환합니다.
결과: 브라우저가 캐시된 버전을 재사용하므로 대역폭과 시간이 절약됩니다.
Stale‑While‑Revalidate
Cache-Control: max-age=60, stale-while-revalidate=600
- Fresh (≤ 60 s): 캐시에서 즉시 제공됩니다.
- Stale (60 s – 600 s): 오래된 응답을 즉시 제공하고, 백그라운드에서 최신 복사본을 가져와 캐시를 업데이트합니다.
이렇게 하면 로딩 스피너를 없애면서 데이터가 적절히 최신 상태를 유지합니다.
깊이 살펴보기: web.dev – Love your cache (stale‑while‑revalidate)
왜 이것이 React 개발자에게 중요한가
프론트엔드 개발자라서 서버 헤더를 설정하지 않는다 생각할 수도 있습니다.
현실은 HTTP로 깨뜨린 것을 JavaScript로 고칠 수 없다는 것입니다.
- API가
Cache-Control: no-store를 보낸다면, React Query(TanStack Query) 같은 라이브러리는 브라우저가 응답을 저장하지 않기 때문에 효과적인 클라이언트‑사이드 캐시를 유지할 수 없습니다. - API가 사용자 프로필에 대해
max-age=31536000(1 년) 을 보낸다면, 캐시가 만료될 때까지 사용자는 프로필 업데이트를 전혀 보지 못합니다.
조치: Chrome DevTools → Network 탭에서 응답 헤더를 확인하세요. 브라우저의 “영수증” 시스템(조건부 요청)을 통해 리소스가 변경되지 않았을 때(304) 불필요한 다운로드를 방지할 수 있습니다.
사용자 경험 이점
- Stale‑while‑revalidate 는 오래된 데이터를 즉시 보여주면서 백그라운드에서 최신 데이터를 가져와, 로딩 스피너가 필요 없게 합니다.
- 적절한 캐시 헤더는 지연 시간과 대역폭 사용을 줄이고, 인지된 성능을 향상시킵니다.
Deep Dive Resources
- MDN HTTP Caching Guide – 브라우저가 스토리지를 처리하는 방법에 대한 포괄적인 매뉴얼.
- Google Web.dev Guide – 성능 및 Lighthouse 점수를 위한 헤더 구성에 대한 실용적인 가이드.
- Cloudflare CDN Learning Center – 엣지 캐시가 브라우저 캐시와 상호 작용하는 방식을 이해하기.
다음은?
보이지 않는 레이어를 이해했으니, 이제 Application Layer로 이동할 수 있습니다. Part 3에서는 **React Query (TanStack Query)**를 살펴보고, 이를 사용해 효율적인 캐싱 시스템을 구현하는 방법을 알아볼 것입니다.
Part 3에서 뵙겠습니다.