본문 바로가기
MAKESITE
무료 스캔 문의하기 로그인

점검 항목 · 성능

정적 자산 캐시 헤더 없음

헤더를 넣는 것은 한 줄입니다. 어려운 것은 캐시를 길게 걸어 두고도 배포한 순간 새 파일이 적용되게 만드는 것입니다.

심각도 낮음 성능 무료 스캔 판정 항목 /check/cache-headers

01DEFINITION

한 줄로 말하면

로고 · CSS · 폰트처럼 몇 달 동안 바뀌지 않는 파일에 캐시 지시가 없으면, 방문자가 페이지를 옮길 때마다 같은 파일을 다시 내려받습니다. 재방문자의 체감 속도가 첫 방문과 똑같아지고 서버 트래픽도 그만큼 낭비됩니다. 파일 이름에 버전을 붙여 두면 캐시 기간을 길게 잡아도 배포한 순간 새 파일이 적용됩니다.

02RISK

없으면 무슨 일이 생기나

캐시 지시가 없으면 브라우저는 그 파일을 보관해도 되는지 확신하지 못합니다. 결과적으로 페이지를 옮길 때마다 로고와 스타일시트와 폰트를 다시 받거나, 최소한 바뀌었는지 물어보는 왕복을 매번 합니다. 두 번째 방문이 첫 방문만큼 느려지고, 서버 쪽에서는 같은 파일을 하루에 수천 번 다시 내보냅니다.

반대로 캐시를 길게 걸어 두면 이번에는 고친 것이 반영되지 않습니다. 스타일시트를 고쳐 배포했는데 이미 방문한 적 있는 사람은 캐시 기간이 끝날 때까지 옛 화면을 봅니다. 저희도 이 사고를 냈습니다. 압축과 캐시를 켜면서 스타일시트에 30일 캐시를 걸었는데, 그 뒤에 CSS 를 고쳐도 재방문자는 옛것을 보고 있었습니다.

그래서 이 항목은 캐시 기간만의 문제가 아닙니다. 파일이 바뀌었을 때 주소도 함께 바뀌게 만드는 것까지가 한 세트이고, 그 장치가 없으면 캐시를 짧게 걸 수밖에 없어 효과가 반감됩니다.

03CHECK IT YOURSELF

직접 확인하는 방법

아래는 저희를 거치지 않고 지금 해 보실 수 있는 방법입니다. 결과를 저희에게 보내실 필요도 없습니다.

  1. 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
  2. 02
    HTML 에는 캐시가 걸려 있지 않은지 확인한다

    정적 파일과 반대입니다. HTML 을 오래 캐시하면 가격이나 재고를 고쳐도 반영되지 않습니다. HTML 은 캐시하지 않는 것이 원칙입니다.

    $ curl -sI https://example.com/pricing | grep -i cache-control
  3. 03
    재방문 시 실제로 다시 받는지 본다

    개발자도구 네트워크 탭에서 두 번째 방문을 보면, 캐시가 듣는 파일은 크기 칸에 캐시에서 가져왔다고 표시됩니다. 매번 숫자가 찍혀 있으면 다시 받고 있는 것입니다.

  4. 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 은 캐시하지 않는다

내용이 바뀌면 즉시 보여야 하는 것은 캐시하지 않습니다. 정적 파일 규칙을 만들 때 HTML 이 딸려 들어가지 않도록 형식을 명시하십시오.

서버에 없는 모듈에 의존하지 않는다

캐시 설정에는 여러 방법이 있고 환경마다 있는 모듈이 다릅니다. 한쪽만 적어 두면 그 모듈이 없는 서버에서 조용히 무시됩니다. 두 방식을 함께 적어 두면 어느 환경에서도 동작합니다.

주의. immutable 을 붙인 파일은 브라우저가 새로고침해도 다시 확인하지 않습니다. 주소에 버전이 확실히 붙어 있는 파일에만 쓰십시오. 버전 없이 붙이면 그 파일은 캐시 기간이 끝날 때까지 갱신할 방법이 사실상 없습니다.

05FAQ

자주 묻는 질문

캐시 기간을 얼마로 잡아야 하나요

주소에 버전이 붙어 있다면 1년으로 잡아도 안전합니다. 버전이 없다면 배포 주기보다 짧게 잡아야 하는데, 그러면 효과가 크게 줄어듭니다. 그래서 순서는 버전을 붙이는 것이 먼저이고 기간을 늘리는 것이 나중입니다.

ETag 나 Last-Modified 만 있어도 되나요

이 값들은 바뀌었는지 물어보는 데 쓰입니다. 다시 받지는 않아도 왕복 한 번은 매번 발생합니다. 파일이 수십 개면 그 왕복이 쌓입니다. 아예 묻지 않게 하는 Cache-Control 이 있어야 효과가 제대로 납니다.

고쳤는데 방문자 화면이 그대로라고 합니다

캐시가 듣고 있는 것이고, 파일 주소가 그대로이기 때문입니다. 임시로는 강제 새로고침을 안내할 수 있지만 모든 방문자에게 그럴 수는 없습니다. 파일 주소에 버전을 붙이는 방식으로 바꾸는 것이 근본 해결입니다.

로그인한 사용자에게만 다른 내용이 보이는 페이지는요

그런 페이지는 공용 캐시에 저장되면 안 됩니다. private 로 지정하거나 아예 캐시하지 않도록 하십시오. 다른 사람의 개인 화면이 캐시를 통해 보이는 사고가 여기서 나옵니다.
여기까지는 항목 일반론입니다. 무엇이고 왜 문제이며 어떻게 고치는지는 감출 이유가 없어 그대로 적었습니다. 리포트에 들어가는 것은 귀사 사이트에서 실제로 어떤 값이 나왔는지 — 어느 주소의 어느 응답인지, 그 환경에서 어떤 순서로 적용해야 하는지, 예상 공수가 얼마인지입니다. 이 페이지만 보고 직접 고치셔도 되고, 실제로 그러시라고 적어 두었습니다.

GET STARTED

내 사이트는
이 항목을 통과할까요

주소만 넣으시면 이 항목을 포함해 25가지를 판정해 점수와 실패 개수를 보여 드립니다. 로그인도, 소유 확인도 필요 없습니다 — 전부 밖에서 관찰만 하는 항목이기 때문입니다.