메인 콘텐츠로 건너뛰기
Deep Thought
← 목록으로
Frontend

Cache-Control 헤더로 웹 성능 최적화하기

신중선-- views
cache-controlweb-performancehttp-headersbrowser-cache

Cache-Control 헤더란?

Cache-Control은 HTTP 응답에서 클라이언트(브라우저)와 중간 서버(proxy, CDN)가 리소스를 어떻게 캐싱할지 지시하는 핵심 헤더입니다. 서버가 "이 리소스를 얼마나 오래, 어떤 방식으로 저장해도 되는가"를 명시적으로 알려주는 역할을 합니다.

웹 페이지 로딩 시 브라우저는 HTML, CSS, JavaScript, 이미지 등 다양한 리소스를 다운로드합니다. 이때 매번 서버에서 새로 받아오는 대신, 적절히 캐싱된 데이터를 활용하면 네트워크 요청을 줄이고 로딩 속도를 크게 개선할 수 있습니다.

Cache-Control 헤더를 통해 리소스별로 최적화된 캐싱 정책을 수립할 수 있으며, 이는 사용자 경험과 서버 부하 감소에 직접적인 영향을 미칩니다.

핵심 개념

1. 주요 디렉티브와 동작 방식

Cache-Control은 여러 디렉티브를 조합하여 세밀한 캐싱 제어가 가능합니다.

# 정적 리소스 - 1년간 캐시, 변경 불가능
Cache-Control: public, max-age=31536000, immutable

# HTML 문서 - 캐시하되 매번 검증 필요
Cache-Control: no-cache, must-revalidate

# 민감한 데이터 - 캐시 금지
Cache-Control: no-store, private

시간 기반 디렉티브:

  • max-age: 리소스가 유효한 시간(초)
  • s-maxage: 공유 캐시(CDN)에서의 유효 시간

캐시 위치 제어:

  • public: 모든 캐시에서 저장 가능
  • private: 브라우저에만 저장 가능

캐시 동작 제어:

  • no-cache: 캐시하되 사용 전 서버 검증 필수
  • no-store: 캐시 저장 금지
  • must-revalidate: 캐시 만료 시 반드시 재검증

2. 리소스별 캐싱 전략

각 리소스 유형에 따라 다른 캐싱 전략을 적용해야 합니다.

// Express.js 예시
app.use('/static', express.static('public', {
  setHeaders: (res, path) => {
    if (path.endsWith('.html')) {
      // HTML: 항상 최신 상태 유지
      res.setHeader('Cache-Control', 'no-cache, must-revalidate');
    } else if (path.match(/\.(css|js)$/)) {
      // CSS/JS: 버저닝된 파일은 장기 캐시
      res.setHeader('Cache-Control', 'public, max-age=31536000, immutable');
    } else if (path.match(/\.(jpg|png|gif|ico)$/)) {
      // 이미지: 중기 캐시
      res.setHeader('Cache-Control', 'public, max-age=2592000');
    }
  }
}));

정적 리소스 (CSS, JS, 이미지):

  • 파일명에 해시값 포함 시: public, max-age=31536000, immutable
  • 일반 정적 파일: public, max-age=2592000

동적 콘텐츠 (HTML, API):

  • 자주 변경: no-cache, must-revalidate
  • 민감한 데이터: no-store, private

3. 캐시 검증과 조건부 요청

Cache-Control과 함께 ETag나 Last-Modified 헤더를 활용하면 효율적인 캐시 검증이 가능합니다.

# 서버 응답
Cache-Control: no-cache, must-revalidate
ETag: "abc123"
Last-Modified: Wed, 21 Oct 2025 07:28:00 GMT

# 브라우저 재요청
If-None-Match: "abc123"
If-Modified-Since: Wed, 21 Oct 2025 07:28:00 GMT

브라우저는 no-cache 디렉티브를 만나면 캐시된 데이터가 있어도 서버에 조건부 요청을 보냅니다. 서버가 304 Not Modified로 응답하면 캐시된 데이터를 사용하고, 200 OK로 응답하면 새 데이터를 받아옵니다.

4. CDN과 다층 캐싱 제어

CDN과 브라우저 캐시를 별도로 관리할 때는 s-maxage와 max-age를 조합합니다.

# CDN에서는 24시간, 브라우저에서는 1시간 캐시
Cache-Control: public, max-age=3600, s-maxage=86400

# CDN 캐시 무효화 후 브라우저도 재검증
Cache-Control: public, max-age=0, s-maxage=0, must-revalidate

이를 통해 CDN에서는 오래 캐시하되 브라우저에서는 짧게 캐시하여, 콘텐츠 업데이트 시 유연하게 대응할 수 있습니다.

정리

디렉티브 용도 적용 사례
public, max-age=31536000, immutable 장기 캐시 해시 기반 정적 파일
no-cache, must-revalidate 항상 검증 HTML, 중요한 API
no-store, private 캐시 금지 인증 정보, 개인 데이터
public, max-age=3600 단기 캐시 자주 변경되는 이미지
public, max-age=0, must-revalidate 즉시 재검증 긴급 업데이트 필요 시

Cache-Control을 효과적으로 활용하면 불필요한 네트워크 요청을 줄이고 페이지 로딩 속도를 개선할 수 있습니다. 특히 모바일 환경에서는 데이터 사용량 절약과 성능 향상 효과가 더욱 두드러집니다. 리소스 특성에 맞는 캐싱 전략을 수립하여 최적의 사용자 경험을 제공하는 것이 중요합니다.

References