HTTP 캐시는 리소스를 디스크 혹은 메모리에 저장하여 서버에 요청을 보내지 않고 사용할 수 있도록 재는 기능입니다. 덕분에 사용자 경험을 향상시켜주는 아주 좋은 기능이지만, 때로는 원하지 않는 오래된 리소스를 사용하게 될 수 있기 때문에 유효 기간을 잘 설정해야합니다. 이 유효 기간을 설정할 수 있는 방법이 바로 HTTP의 Cache-Control 헤더입니다. 이번 글에서 HTTP의 Cache-Control을 통해 캐시의 유효 기간을 설정하는 방법에 대해서 알아보겠습니다.
max-age
서버의 Cache-Control 헤더 값으로 `max-age=<seconds>`를 설정하면, 해당 리소스의 캐시 유효 기간을 해당 초로 설정하게 됩니다. 유효 기간이 지나기 전까지는 브라우저는 서버에 요청을 보내지 않고, 캐시를 읽어와 리소스를 사용하게 됩니다. 그렇다면 유효 기간이 지나면 어떻게 될까요? 바로 재검증을 통해 해당 리소스를 더 사용할 수 있을지 확인합니다.
Revalidation
브라우저는 서버에 조건부 요청을 보내 캐시가 유효한지를 확인합니다. 만약 유효하다면 304 응답을 내려주게 되는데, 이는 본문을 포함하지 않아 아주 빠르게 응답을 받을 수 있습니다. 유효한지 확인하는 방법은 2가지가 있습니다.
If-Modified-Since
If-Modified-Since를 활용하기 위해선 Last-Modified 헤더 값이 응답에 설정이 되어있어야 합니다. 캐시가 유효 기간이 지나 'stale' 상태가 되면, 브라우저에서는 캐시된 리소스이 Last-Modified값을 If-Modified-Since 값으로 설정하여 서버에 요청을 보내게 됩니다. 만약 변경되지 않았다면 304 응답을 내려주게 되고, 캐시의 유효 기간은 다시 max-age 값으로 설정됩니다. 그러나 이러한 방법은 서버가 os에서 시간을 가져와야 하며, 여러 서버에서 파일 업데이트 시간을 동기화하기 어렵다는 문제점이 생깁니다. 따라서, Etag를 활용한 방법이 다 많이 사용됩니다.
If-None-Match
Etag는 쉽게 말해 리소스의 해시 값입니다. 즉 리소스의 값이 변경되면 Etag도 값이 변경되게 됩니다. Etag를 사용한 방법에서는 If-None-Match라는 헤더를 사용하게 되는데, 캐시된 리소스의 Etag를 서버에 보내서 Etag가 동일한지를 확인하여 캐시의 유효성을 검사합니다.
그렇다면 더 좋은 방법인 Etag를 활용한 If-None-Match만 설정하면 될까요? 그렇지 않습니다. RFC9110에서는 두 헤더를 모두 설정하는 것을 권장하는데, 이는 단순히 캐시와 관련된 이유는 아닙니다. Last-Modified 값은 캐싱에서 If-None-Match 보다 우선순위가 낮으므로 사용되지 않을 수 있지만, CMS에서 최근 변경된 시간으로 표시하거나, 크롤러가 크롤링 주기를 조절하거나 등등 여러 다를 용도로도 사용됩니다. 따라서 두 헤더 모두 설정하는 것이 좋습니다.
No-Cache, No-Store
Max-age를 설정하는 대신 이 두가지의 헤더 값을 설정할 수도 있습니다.
no-cache는 대부분의 브라우저에서 max-age=0과 같은 의미를 가집니다. 즉 캐시를 저장은 하지만, 매번 서버에 재검증 요청을 보내야한다는 겁니다.
no-store는 캐시를 절대로 해서는 안되는 리소스를 의미하며, 아예 캐시를 하지 말라는 의미입니다.
Public, Private
이 외에도 public, private 헤더 값이 있는데 이는 CDN과 관련된 값들입니다.
Public은 모든 사람과 중간 서버가 캐시를 저장할 수 있음을 나타내며, Private은 가장 끝의 사용자만 브라우저에 캐시를 저장할 수 있음을 나타냅니다. Cache-control의 값은 하나만 지정할 필요는 없으며, 여러 값을 지정할 경우 콤마로 구분하여 설정할 수 있습니다.
리소스의 성격에 따른 Cache-Control
리소스에 따라 캐시 헤더 값을 다르게 설정하는데, 일반적으로 HTML은 매번 캐시를 검증할 수 있도록 max-age=0 혹은 no-cache를 사용합니다. no-store를 사용할 수 도 있습니다. JS, CSS 파일의 경우 빌드시에 파일에 해시 값을 추가하는 경우가 많기 때문에 내용이 바뀔 일이 없습니다. 따라서 최대치의 max-age 값인 31536000으로 설정하여도 무방합니다.
참고 문서
'개발 용어 정리' 카테고리의 다른 글
| 컴포넌트 주도 개발(Component-Driven Development)이란? (0) | 2023.01.29 |
|---|---|
| Monorepo란? (0) | 2022.09.08 |