Cache-Control의 no-cache와 no-store 차이: 저장을 막는 쪽은 no-store다

no-cache는 캐시하지 말라는 뜻이 아닙니다. RFC 9111 기준으로 no-cache와 no-store, max-age=0, Pragma의 차이를 정리하고, CDN과 브라우저에서 동작이 달라지는 지점을 짚습니다.

개발웹네트워크

개발자 도구를 보면 Cache-Control: no-cache가 붙은 응답도 캐시 항목으로 나타날 수 있습니다. HTTP 캐시 명세 RFC 9111에서 no-cache는 그 자체로 저장을 금지하지 않습니다. 저장할 수 있는지는 다른 규칙이 정하고(3절), no-cache는 저장된 응답을 다시 쓰기 전에 원 서버 검증을 요구합니다. 저장을 막는 지시어는 no-store입니다.

no-cache: 재사용할 때마다 검증

인자 없는 no-cache가 붙은 응답은 원 서버 검증에 성공하기 전에는 다른 요청에 재사용할 수 없습니다(5.2.2.4절). 응답 전체를 검증할 때 캐시는 저장된 ETag를 If-None-Match로 보냅니다(4.3.1절). 응답이 아직 유효하면 서버는 본문 없는 304 Not Modified로 답할 수 있습니다(RFC 9110 15.4.5절).

max-age=0도 응답을 곧바로 stale로 만듭니다. 하지만 캐시가 원 서버와 연결이 끊겼거나 클라이언트가 max-stale로 허용하면 stale 응답을 낼 수 있습니다(4.2.4절). no-cache는 stale 응답을 내도록 설정된 캐시에서도 검증 없는 재사용을 막습니다.

no-store: 저장하지 말라는 지시

no-store는 해당 요청과 응답의 어떤 부분도 저장하지 말라는 뜻이며, private 캐시와 shared 캐시에 모두 적용됩니다(5.2.2.5절). no-cache와 함께 오면 보통 저장되지 않습니다. 다만 must-understand를 구현한 캐시가 그 상태 코드의 캐시 규칙을 이해하면 no-store를 무시하도록 권장됩니다(5.2.2.3절). 명세는 no-store가 개인정보를 지키는 확실하거나 충분한 수단이 아니라고도 밝힙니다. 이를 따르지 않는 캐시나 도청은 막지 못합니다.

CDN과 브라우저에서 동작이 달라지는 곳

  • no-cache="Set-Cookie"처럼 필드를 지정하면, 명세상 그 필드를 뺀 경우에만 검증 없이 재사용할 수 있습니다. 하지만 이 형태는 널리 구현되지 않아 많은 캐시가 인자 없는 no-cache처럼 다룹니다(5.2.2.4절). Set-Cookie 헤더만으로는 캐시 가능한 응답이 캐시되는 것을 막지 못합니다(7.3절).
  • Cloudflare 문서에 따르면 Origin Cache Control이 켜져 있으면 no-cache 응답을 캐시하고 매번 재검증하며, 꺼져 있으면 캐시하지 않습니다. Free·Pro·Business 요금제에서는 켜져 있고 끌 수 없습니다.
  • 뒤로/앞으로 가기 캐시(bfcache)는 HTTP 캐시가 아닙니다. web.dev에 따르면 no-store가 붙은 페이지는 그동안 bfcache에서 제외돼 왔고, Chrome에서는 이를 바꾸는 작업이 진행 중입니다. bfcache에서 복원할 때는 no-cache나 max-age=0이 적용되지 않습니다. 그래서 web.dev는 복원 뒤 새 내용이 필요하면 pageshow 이벤트로 처리하라고 안내합니다. 브라우저와 버전에 따라 달라질 수 있습니다.
  • Pragma: no-cache는 HTTP/1.0용 요청 헤더로, 비권장으로 지정됐습니다. 응답에서는 의미가 정의된 적이 없습니다(5.4절).

민감하지 않고 재사용 전에 재검증하면 되는 HTML이나 API 응답에는 no-cache와 ETag를 씁니다. 저장되면 안 되는 응답에는 no-store를 쓰되 HTTPS 같은 보호를 따로 둡니다. 리다이렉트의 캐시 규칙은 301, 302, 307, 308 리다이렉트의 차이에서 다뤘습니다.

블로그로