Кэширование статики: Cache-Control, ETag, immutable — по шагам

Как настроить кэш статики, чтобы повторные заходы были мгновенными, а деплой ничего не ломал: Cache-Control, max-age, immutable, версионирование файлов, ETag и пример конфигурации nginx.

Статика — CSS, JS, шрифты, картинки — почти не меняется, но по умолчанию браузер тянет её заново при каждом заходе. Правильные кэш-заголовки заставляют браузер хранить файлы локально и не дёргать сервер месяцами. Разберём Cache-Control, ETag и приём с immutable по шагам.

Как работает кэш статики

При первом запросе сервер отдаёт файл вместе с заголовками, которые говорят браузеру: «храни это и не спрашивай меня N секунд». Дальше браузер берёт файл из локального кэша мгновенно, без обращения к сети. Управляет этим в первую очередь заголовок Cache-Control.

Cache-Control: главные директивы

  • max-age=31536000 — сколько секунд файл считается свежим (здесь — год).
  • public — кэшировать можно всем, включая CDN и прокси.
  • private — только браузер пользователя, для персональных ответов.
  • immutable — файл не изменится никогда; браузер не переспрашивает даже при перезагрузке страницы.

Рабочая комбинация для статики: Cache-Control: public, max-age=31536000, immutable.

Версионирование = кэш на год

«Кэшировать на год» звучит страшно: а как выкатывать обновления? Ответ — версионировать имя файла. Сборщик добавляет хэш содержимого:

app.js      →  app.9f2c1a.js
styles.css  →  styles.4be07d.css

Изменился файл — изменился хэш — изменился URL, и браузер скачивает новый как «другой» файл. Старый кэш при этом не мешает. Поэтому HTML кэшируем коротко (или совсем нет), а версионированную статику — на год с immutable.

ETag против Last-Modified

Эти заголовки нужны для проверки «а не устарел ли файл», когда max-age истёк:

  • Last-Modified — дата изменения; браузер шлёт If-Modified-Since, сервер отвечает 304, если файл не менялся.
  • ETag — «отпечаток» содержимого; точнее даты, но на кластере из нескольких серверов ETag может отличаться и ломать 304.

При версионировании имён валидаторы почти не нужны — до истечения года браузер вообще не ходит на сервер. ETag полезнее для неверсионируемых ресурсов.

Пример настройки nginx

location /static/ {
    expires 1y;
    add_header Cache-Control "public, immutable";
    access_log off;
}

location = /index.html {
    add_header Cache-Control "no-cache";
}

Статику — на год, HTML — no-cache, чтобы новая версия страницы с новыми ссылками на файлы подхватывалась сразу.

Грабли

  • Неверсионированная статика с длинным max-age. Обновили style.css, а половина пользователей месяц видит старый — он у них в кэше. Либо версионируйте, либо не ставьте большой max-age.
  • Забыли про HTML. Если и HTML закэширован надолго, новые хэши файлов не подхватятся. HTML — короткий кэш.
  • ETag на кластере. Разные ноды — разные ETag, 304 не срабатывает. Отключите ETag или синхронизируйте.
  • Забыли инвалидацию на CDN. После деплоя неверсионированных файлов сбросьте кэш CDN (purge), иначе он отдаёт старое.

Вывод

Схема простая: версионируйте имена файлов, отдавайте статику с max-age на год и immutable, а HTML держите на коротком кэше. Тогда повторные заходы становятся почти мгновенными, а деплой ничего не ломает. Если хотите настроить кэш и заголовки без риска словить «застрявшую» старую версию, оптимизируем скорость вашего сайта — от диагностики до внедрения CDN и кэша.

Оптимизация скорости и CDN
Услуга по теме — обсудим ваш проект.