HTTP 캐싱: 브라우저가 요청을 줄이는 방법

Cache-Control 헤더와 ETag를 중심으로 HTTP 캐싱의 핵심 원리를 정리합니다.

2024년 4월 22일


웹 성능 최적화를 이야기할 때 캐싱을 빼놓을 수 없다. 같은 이미지, 같은 JS 파일을 매 요청마다 서버에서 새로 받아오는 건 낭비다. 브라우저가 이미 가지고 있는 걸 활용하면 되는데, 그 기준을 정하는 게 HTTP 캐싱이다.


1. HTTP 캐싱이란?

한 번 받아온 리소스를 브라우저나 중간 서버(CDN)에 저장해두고, 다음 요청 때 서버에 다시 가지 않고 재사용하는 기술이다.

첫 방문과 재방문의 속도 차이가 느껴진다면, 십중팔구 캐싱이 제대로 작동하고 있다는 뜻이다.


2. Cache-Control 헤더

HTTP 캐싱의 핵심은 Cache-Control 응답 헤더다. 서버가 브라우저에게 캐시 저장 방식을 지시하는 헤더다.

자주 쓰이는 옵션들

  • max-age=3600: "앞으로 1시간 동안은 서버에 묻지 말고 이 파일을 그대로 써." 정적 에셋(이미지, 번들된 JS)에 주로 쓴다.
  • no-cache: 캐시는 저장하되, 매번 서버에 "이거 아직 써도 돼?"라고 검증 요청을 보낸다. 저장을 막는 게 아니라 검증을 강제하는 옵션이다.
  • no-store: 절대 저장하지 않는다. 매번 새로 받아와야 하는 민감한 정보에 사용한다.
  • public: CDN 같은 중간 서버에도 저장할 수 있다.
  • private: 오직 사용자의 브라우저에만 저장한다. 로그인한 사용자 데이터처럼 개인화된 응답에 쓴다.

no-cacheno-store는 이름이 비슷해서 자주 헷갈린다. no-cache는 저장은 하고 매번 확인, no-store는 저장 자체를 금지한다.


3. 데이터가 변했는지 확인하는 법: ETag

no-cache를 쓰면 브라우저는 매 요청마다 서버에 확인을 보낸다. 그런데 서버가 어떻게 "데이터 안 바뀌었으니 캐시 써도 돼"라고 알려줄까?

이때 사용하는 게 **ETag(Entity Tag)**다. 리소스의 버전을 식별하는 해시값이다.

  1. 첫 요청: 서버가 리소스와 함께 ETag: "abc123" 헤더를 반환한다.
  2. 재요청: 브라우저가 If-None-Match: "abc123" 헤더를 포함해 유효성을 확인한다.
  3. 응답: 데이터가 변경되지 않았다면 서버는 본문 없이 **304 Not Modified**만 반환한다. 브라우저는 기존 캐시를 그대로 쓴다.

데이터가 바뀌었다면 서버가 새 리소스와 새 ETag를 담아 200 OK로 응답한다. no-cache와 ETag를 함께 쓰면 매번 확인하되 변경이 없을 때 304로 처리해 대역폭을 절약할 수 있다.


마무리

  • max-age: 만료 기간 안에는 서버에 아예 묻지 않는다. 빠르지만, 배포 직후 구버전 파일이 보일 수 있다.
  • no-cache + ETag: 매번 확인은 하지만, 변경이 없으면 304로 트래픽을 아낀다.
  • no-store: 캐시 없음. 민감한 데이터에만 쓰는 게 맞다.

보통 정적 에셋에는 max-age를 길게 주고 파일명에 해시를 붙여 배포하고, API 응답에는 no-cache를 적용하는 조합을 많이 쓴다.