Conceptly
← 전체 목록

HTTP Caching

performanceHTTP 헤더 기반 브라우저·프록시 캐시 제어 메커니즘

HTTP 캐싱은 서버의 응답을 브라우저나 프록시에 저장해 두었다가 같은 요청이 다시 올 때 네트워크를 거치지 않고 저장된 응답을 바로 돌려주는 메커니즘입니다. 핵심은 응답 헤더, 특히 Cache-Control에 담긴 지시어를 따라 캐시 계층이 언제 저장하고, 언제 그냥 돌려주고, 언제 서버에 다시 물어볼지를 결정한다는 점입니다.

아키텍처 다이어그램

📊 데이터 흐름 다이어그램

점선 애니메이션은 데이터 또는 요청의 흐름 방향을 나타냅니다

왜 필요한가요?

웹 페이지를 열 때 브라우저는 수십에서 수백 개의 자산을 내려받습니다. 로고 이미지, 폰트 파일, 라이브러리 번들은 매 방문마다 바뀌지 않는데도 매번 서버에서 동일한 파일을 다시 받는다면 시간도 낭비고 서버 부하도 불필요하게 쌓입니다. 거꾸로 캐시를 너무 과하게 쓰면 배포 직후 업데이트된 파일 대신 오래된 파일이 사용자에게 계속 전달되는 문제가 생깁니다. 캐시를 전혀 쓰지 않거나 제대로 통제하지 않으면 성능과 신선도 사이에서 항상 불필요한 트레이드오프를 감수하게 됩니다.

왜 이런 방식이 등장했나요?

초기 HTTP 스펙은 캐싱에 대한 정의가 느슨했습니다. Expires 헤더처럼 절대 날짜·시간을 쓰던 방식은 클라이언트와 서버의 시계가 어긋나면 예측하기 어려운 동작을 낳았습니다. HTTP/1.1에서 Cache-Control 헤더가 도입되면서 상대적 신선도(max-age), 공유 캐시 제어(s-maxage), no-cache·no-store 같은 세밀한 지시어가 한 헤더에 통합됐습니다. 이후 ETag와 조건부 GET이 더해지면서 '캐시가 만료됐더라도 실제 내용이 바뀌지 않았다면 본문을 다시 전송하지 않는다'는 재검증 패턴이 정착했습니다. 오늘날 CDN이 전역 배포의 기반이 되면서 Cache-Control을 통한 캐시 수명 관리는 성능 최적화의 첫 번째 도구가 됐습니다.

내부적으로 어떻게 동작하나요?

브라우저가 리소스를 요청하면 먼저 캐시를 확인합니다. 저장된 응답이 있고 max-age 안에 들어온다면 네트워크를 거치지 않고 바로 반환합니다. 저장은 됐지만 max-age가 지났다면 서버에 If-None-Match(ETag 값)나 If-Modified-Since 헤더를 실어 조건부 요청을 보냅니다. 서버는 실제 내용이 바뀌지 않았으면 본문 없이 304 Not Modified만 돌려주고, 브라우저는 기존 캐시를 그대로 쓰면서 유효 기간만 갱신합니다. 아예 캐시가 없거나 no-store 지시어가 있으면 매번 전체 응답을 받습니다. Cache-Control: no-cache는 이름과 달리 캐시를 쓰지 않겠다는 의미가 아니라 '사용하기 전에 반드시 재검증하라'는 의미입니다.

경계와 구분

HTTP 캐싱과 Service Worker 캐싱은 둘 다 네트워크 요청을 줄이고 응답 속도를 높이는 목적을 가지지만, 작동하는 계층과 제어 주체가 다릅니다. HTTP 캐싱은 브라우저와 HTTP 스펙이 자동으로 처리하는 인프라 수준의 캐시입니다. Cache-Control 헤더 값으로 동작을 지정하면 그에 따라 브라우저나 CDN이 알아서 움직입니다. Service Worker 캐싱은 개발자가 직접 JS로 작성하는 프로그래밍 캐시입니다. 어떤 요청을 가로채고, 어떤 응답을 어디에 저장하고, 언제 꺼내 쓸지를 코드로 결정하기 때문에 오프라인 지원, 요청 가로채기, 동적 캐시 전략처럼 HTTP 헤더만으로는 할 수 없는 시나리오를 처리할 수 있습니다. HTTP 캐싱으로 기본 성능을 잡고, 더 세밀한 오프라인·전략이 필요할 때 Service Worker가 추가되는 식으로 함께 쓰는 경우가 많습니다. SSG(정적 사이트 생성)와 HTTP 캐싱은 서로 다른 계층에서 동작하지만 자연스럽게 연결됩니다. SSG는 빌드 시점에 HTML을 만들어 두기 때문에 응답이 정적 파일이 되고, 정적 파일은 내용이 바뀌지 않는 한 CDN과 브라우저에서 캐시하기 가장 쉬운 형태입니다. 해시 기반 파일명(예: main.a1b2c3.js)을 쓰면 변경 시 URL 자체가 달라지므로 max-age를 1년처럼 길게 설정해도 배포와 캐시 무효화 문제가 동시에 해결됩니다.

언제 쓰나요?

실무에서 HTTP 캐싱을 제대로 활용하려면 리소스 유형별로 전략을 분리해야 합니다. 번들 파일명에 콘텐츠 해시가 포함된 JS·CSS·이미지는 Cache-Control: public, max-age=31536000, immutable로 1년간 캐시해도 안전합니다. URL이 고정된 HTML 문서나 API 응답은 no-cache나 짧은 max-age를 설정해 항상 최신 상태를 확인하도록 합니다. CDN을 쓸 때는 s-maxage로 엣지 캐시 수명을 브라우저 캐시와 독립적으로 관리하고, 배포 시 CDN 무효화(cache purge)를 함께 자동화하면 오래된 응답이 엣지에 남는 문제를 예방할 수 있습니다. 캐싱 문제는 대부분 'Cache-Control을 아예 설정하지 않아서' 또는 '같은 URL로 다른 내용을 서빙하면서 무효화를 빠뜨려서' 발생합니다. 새로운 기능을 출시했는데 일부 사용자에게 이전 화면이 보인다면 가장 먼저 캐시 정책과 배포 파이프라인을 같이 점검하는 것이 좋습니다.

정적 자산 최적화API 응답 캐싱CDN 통합재검증 전략