Кэширование статики: 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 и кэша.