01DEFINITION
한 줄로 말하면
로고 · CSS · 폰트처럼 몇 달 동안 바뀌지 않는 파일에 캐시 지시가 없으면, 방문자가 페이지를 옮길 때마다 같은 파일을 다시 내려받습니다. 재방문자의 체감 속도가 첫 방문과 똑같아지고 서버 트래픽도 그만큼 낭비됩니다. 파일 이름에 버전을 붙여 두면 캐시 기간을 길게 잡아도 배포한 순간 새 파일이 적용됩니다.
02RISK
없으면 무슨 일이 생기나
캐시 지시가 없으면 브라우저는 그 파일을 보관해도 되는지 확신하지 못합니다. 결과적으로 페이지를 옮길 때마다 로고와 스타일시트와 폰트를 다시 받거나, 최소한 바뀌었는지 물어보는 왕복을 매번 합니다. 두 번째 방문이 첫 방문만큼 느려지고, 서버 쪽에서는 같은 파일을 하루에 수천 번 다시 내보냅니다.
반대로 캐시를 길게 걸어 두면 이번에는 고친 것이 반영되지 않습니다. 스타일시트를 고쳐 배포했는데 이미 방문한 적 있는 사람은 캐시 기간이 끝날 때까지 옛 화면을 봅니다. 저희도 이 사고를 냈습니다. 압축과 캐시를 켜면서 스타일시트에 30일 캐시를 걸었는데, 그 뒤에 CSS 를 고쳐도 재방문자는 옛것을 보고 있었습니다.
그래서 이 항목은 캐시 기간만의 문제가 아닙니다. 파일이 바뀌었을 때 주소도 함께 바뀌게 만드는 것까지가 한 세트이고, 그 장치가 없으면 캐시를 짧게 걸 수밖에 없어 효과가 반감됩니다.
03CHECK IT YOURSELF
직접 확인하는 방법
아래는 저희를 거치지 않고 지금 해 보실 수 있는 방법입니다. 결과를 저희에게 보내실 필요도 없습니다.
-
01
정적 파일의 응답 헤더를 본다
Cache-Control 이 아예 없으면 이 항목에 걸립니다. max-age 값이 초 단위 보관 기간입니다.
$ curl -sI https://example.com/theme/makesite/css/makesite.css \ | grep -iE "cache-control|expires|etag|last-modified" cache-control: public, max-age=2592000
-
02
HTML 에는 캐시가 걸려 있지 않은지 확인한다
정적 파일과 반대입니다. HTML 을 오래 캐시하면 가격이나 재고를 고쳐도 반영되지 않습니다. HTML 은 캐시하지 않는 것이 원칙입니다.
$ curl -sI https://example.com/pricing | grep -i cache-control
-
03
재방문 시 실제로 다시 받는지 본다
개발자도구 네트워크 탭에서 두 번째 방문을 보면, 캐시가 듣는 파일은 크기 칸에 캐시에서 가져왔다고 표시됩니다. 매번 숫자가 찍혀 있으면 다시 받고 있는 것입니다.
-
04
설정을 넣었는데 안 붙는 경우를 확인한다
캐시 관련 모듈이 서버에 없어서 설정이 무시되는 경우가 실제로 있습니다. 저희 서버도 그랬습니다. 설정을 넣은 뒤 반드시 응답 헤더로 확인하십시오.
$ apachectl -M | grep -E "expires|headers" headers_module (shared) ← expires_module 이 없으면 그쪽 설정은 무시된다
04HOW TO FIX
고치는 방법
서버 환경에 따라 적을 자리가 다릅니다. 아래는 가장 흔한 구성 기준이고, 적용 전에 현재 설정을 백업하십시오.
자주 바뀌는 것과 거의 안 바뀌는 것을 나눕니다. 폰트는 사실상 영구, 이미지는 몇 달, 스타일시트와 스크립트는 배포 주기를 고려해 정합니다.
<IfModule mod_headers.c>
<FilesMatch "\.(css|js)$">
Header set Cache-Control "public, max-age=2592000"
</FilesMatch>
<FilesMatch "\.(png|jpe?g|gif|webp|svg|ico)$">
Header set Cache-Control "public, max-age=15552000"
</FilesMatch>
<FilesMatch "\.(woff2?|ttf|otf)$">
Header set Cache-Control "public, max-age=31536000, immutable"
</FilesMatch>
</IfModule> 이것이 이 항목의 핵심입니다. 파일이 바뀌면 주소도 바뀌게 하면 캐시를 아무리 길게 걸어도 배포 즉시 새 파일이 적용됩니다. 파일 수정 시각을 쓰면 자동으로 갱신됩니다.
<?php $ver = filemtime(__DIR__ . '/css/site.css'); ?> <link rel="stylesheet" href="/css/site.css?ver=<?= $ver ?>">
설치본에 박혀 있는 버전 상수를 그대로 쓰면 우리가 파일을 고쳐도 값이 그대로입니다. 저희가 낸 사고가 정확히 이것이었고, 파일 수정 시각으로 바꿔 해결했습니다.
내용이 바뀌면 즉시 보여야 하는 것은 캐시하지 않습니다. 정적 파일 규칙을 만들 때 HTML 이 딸려 들어가지 않도록 형식을 명시하십시오.
캐시 설정에는 여러 방법이 있고 환경마다 있는 모듈이 다릅니다. 한쪽만 적어 두면 그 모듈이 없는 서버에서 조용히 무시됩니다. 두 방식을 함께 적어 두면 어느 환경에서도 동작합니다.
05FAQ
자주 묻는 질문
캐시 기간을 얼마로 잡아야 하나요
- 주소에 버전이 붙어 있다면 1년으로 잡아도 안전합니다. 버전이 없다면 배포 주기보다 짧게 잡아야 하는데, 그러면 효과가 크게 줄어듭니다. 그래서 순서는 버전을 붙이는 것이 먼저이고 기간을 늘리는 것이 나중입니다.
ETag 나 Last-Modified 만 있어도 되나요
- 이 값들은 바뀌었는지 물어보는 데 쓰입니다. 다시 받지는 않아도 왕복 한 번은 매번 발생합니다. 파일이 수십 개면 그 왕복이 쌓입니다. 아예 묻지 않게 하는 Cache-Control 이 있어야 효과가 제대로 납니다.
고쳤는데 방문자 화면이 그대로라고 합니다
- 캐시가 듣고 있는 것이고, 파일 주소가 그대로이기 때문입니다. 임시로는 강제 새로고침을 안내할 수 있지만 모든 방문자에게 그럴 수는 없습니다. 파일 주소에 버전을 붙이는 방식으로 바꾸는 것이 근본 해결입니다.
로그인한 사용자에게만 다른 내용이 보이는 페이지는요
- 그런 페이지는 공용 캐시에 저장되면 안 됩니다. private 로 지정하거나 아예 캐시하지 않도록 하십시오. 다른 사람의 개인 화면이 캐시를 통해 보이는 사고가 여기서 나옵니다.
GET STARTED
내 사이트는
이 항목을 통과할까요
주소만 넣으시면 이 항목을 포함해 25가지를 판정해 점수와 실패 개수를 보여 드립니다. 로그인도, 소유 확인도 필요 없습니다 — 전부 밖에서 관찰만 하는 항목이기 때문입니다.