Открыть сервис

HTTP-заголовок Cache-Control

Cache-Control — это HTTP-заголовок ответа и запроса, используемый для указания правил кэширования документа (веб-страницы, изображения, файла стилей, скрипта и других ресурсов) в браузерах и промежуточных кэширующих серверах (прокси, CDN). Заголовок определяет, может ли ответ быть сохранён в кэше, на какой срок, и при каких условиях он может быть извлечён из кэша без повторного обращения к исходному серверу. Является ключевым механизмом управления производительностью веб-приложений, позволяя снизить нагрузку на сервер и уменьшить время загрузки страниц для пользователей.

История

Протокол HTTP/1.0 (RFC 1945, 1996 год) содержал заголовок Pragma со значением no-cache, который носил рекомендательный характер и не имел точной спецификации. Для устранения неоднозначностей и предоставления более гибких средств управления кэшированием в спецификации HTTP/1.1 (RFC 2068, 1997 год) был введён заголовок Cache-Control. Впоследствии он был уточнён в RFC 2616 (1999 год), а затем в RFC 7234 (2014 год), который является текущим стандартом (часть HTTP/1.1). В HTTP/2 и HTTP/3 заголовок Cache-Control сохранил свою семантику без изменений.

Синтаксис и директива

Заголовок Cache-Control представляет собой список директив, разделённых запятыми. Каждая директива может иметь необязательный параметр (время в секундах, имя поля, ключевое слово). Регистр директив не чувствителен, однако по соглашению их принято писать в нижнем регистре.

Директивы ответа (от сервера к клиенту)

Эти директивы задаются сервером в HTTP-ответе и управляют поведением кэша на стороне клиента и промежуточных узлов.

  • max-age=<секунды> — указывает максимальное время в секундах, в течение которого ответ считается «свежим» и может быть извлечён из кэша без проверки на сервере. Например, Cache-Control: max-age=3600 разрешает кэширование на один час.
  • s-maxage=<секунды> — аналогичен max-age, но применяется только к общим (shared) кэшам, таким как прокси-серверы и CDN. Игнорируется частными кэшами (браузерами). Имеет приоритет над max-age и Expires для общих кэшей.
  • no-cache — запрещает использование закэшированной копии без предварительной проверки на сервере. Сервер может указать поля, которые необходимо проверить (например, no-cache="Set-Cookie"). Если поля не указаны, кэш должен отправить условный запрос (с заголовками If-Modified-Since или If-None-Match) для каждого использования.
  • no-store — категорически запрещает любое кэширование ответа. Кэш не должен сохранять ни сам ответ, ни его часть на любом носителе. Используется для конфиденциальных данных (банковские выписки, медицинские записи).
  • public — указывает, что ответ может быть закэширован любым кэшем, включая общие. Даже если ответ обычно требует аутентификации, директива public разрешает его кэширование.
  • private — указывает, что ответ предназначен только для одного пользователя и не должен кэшироваться общими кэшами. Браузер пользователя может кэшировать такой ответ. По умолчанию многие ответы считаются private.
  • must-revalidate — обязывает кэш проверять устаревший ответ на сервере перед его использованием. Если сервер недоступен, кэш должен вернуть ошибку 504 Gateway Timeout, а не выдавать устаревший ответ.
  • proxy-revalidate — аналогичен must-revalidate, но применяется только к общим кэшам. Частные кэши (браузеры) игнорируют эту директиву.
  • no-transform — запрещает промежуточным узлам (прокси, CDN) изменять содержимое ответа (например, сжимать изображения, перекодировать шрифты, оптимизировать CSS). Используется для ресурсов, чья целостность критична (например, сертификаты, подписанные файлы).
  • immutable (дополнение RFC 8246, 2017 год) — указывает, что тело ответа не будет изменяться в течение времени его жизни. Браузер может пропустить условные запросы при обновлении страницы, что ускоряет загрузку статических ресурсов.

Директивы запроса (от клиента к серверу)

Эти директивы отправляются браузером или другим клиентом в HTTP-запросе и ограничивают поведение кэша на пути к серверу.

  • max-age=<секунды> — клиент согласен принять ответ, возраст которого не превышает указанное значение. Если ответ в кэше старше, кэш должен переслать запрос на сервер.
  • max-stale[=<секунды>] — клиент согласен принять устаревший ответ. Если указано время, то только ответы, устаревшие не более чем на это время. Если время не указано, принимается любой устаревший ответ.
  • min-fresh=<секунды> — клиент хочет получить ответ, который останется свежим ещё как минимум указанное количество секунд.
  • no-cache — клиент требует, чтобы кэш не выдавал закэшированный ответ без проверки на сервере (условный запрос).
  • no-store — клиент требует, чтобы кэш не сохранял ответ (обычно используется для предотвращения кэширования конфиденциальных данных на промежуточных узлах).
  • no-transform — клиент требует, чтобы промежуточные узлы не изменяли содержимое ответа.
  • only-if-cached — клиент требует, чтобы ответ был получен только из кэша. Если ответа в кэше нет, кэш должен вернуть ошибку 504 Gateway Timeout.

Приоритет и взаимодействие с другими заголовками

Заголовок Cache-Control имеет приоритет над более старыми заголовками управления кэшированием, такими как Expires (HTTP/1.0) и Pragma. Если в ответе присутствует Cache-Control: max-age=0, то заголовок Expires игнорируется. Если Cache-Control отсутствует, браузер может использовать заголовок Expires для определения времени жизни. Заголовок Pragma: no-cache считается эквивалентным Cache-Control: no-cache для обратной совместимости, но его использование не рекомендуется.

Директивы max-age и s-maxage переопределяют значение заголовка Expires. Директива no-cache переопределяет Expires. Директива no-store имеет наивысший приоритет — если она присутствует, кэширование запрещено полностью, независимо от других директив.

Примеры использования

Статические ресурсы (долгое кэширование)

`` Cache-Control: public, max-age=31536000, immutable `` Этот ответ (например, для CSS-файла с хешем в имени) может быть закэширован любым кэшем на один год, и браузер может не проверять его обновления при перезагрузке страницы.

Динамическая страница (проверка при каждом запросе)

`` Cache-Control: no-cache, private `` Ответ (например, для страницы личного кабинета) не должен кэшироваться общими кэшами, но браузер может сохранить его. Однако при каждом запросе браузер должен отправить условный запрос на сервер.

Конфиденциальные данные (запрет кэширования)

`` Cache-Control: no-store `` Ответ (например, для банковской транзакции) не должен сохраняться нигде, включая браузер пользователя.

Управление кэшем для API

`` Cache-Control: private, max-age=60 `` Ответ API (например, для списка заказов) может кэшироваться только браузером пользователя в течение 60 секунд. Прокси-серверы не должны его кэшировать.

Критика и ограничения

Основная критика заголовка Cache-Control связана с его сложностью и возможностью неправильной интерпретации. Неправильная комбинация директив может привести к неожиданному поведению: например, no-cache без указания полей может быть воспринят некоторыми кэшами как no-store. Другая проблема — отсутствие чёткого механизма инвалидации кэша на стороне клиента: если сервер изменил ресурс, браузер может продолжать использовать старую версию до истечения max-age. Для решения этой проблемы используются версионирование URL (включение хеша или номера версии в имя файла) и условные запросы.

Также критикуется избыточность: для простых сценариев (например, статический сайт) достаточно max-age, но разработчики часто добавляют public и immutable без необходимости, что усложняет отладку.

Интересные факты

  • Заголовок Cache-Control является обязательным для HTTP/2 и HTTP/3, хотя его отсутствие не приводит к ошибке — просто кэширование будет работать по умолчанию (обычно ответы считаются private).
  • Директива immutable была предложена компанией Facebook (организация признана экстремистской и запрещена в РФ) в 2017 году для ускорения загрузки статических ресурсов в мобильных браузерах.
  • В некоторых браузерах (например, Chrome) при нажатии кнопки «Обновить» (Ctrl+R) отправляется запрос с Cache-Control: max-age=0, а при принудительном обновлении (Ctrl+Shift+R) — с Cache-Control: no-cache.
  • Заголовок Cache-Control может быть использован для управления кэшированием не только HTTP-ответов, но и других протоколов, основанных на HTTP (например, WebDAV, SOAP).

Источники

  1. RFC 7234 — Hypertext Transfer Protocol (HTTP/1.1): Caching (2014)
  2. RFC 8246 — HTTP Immutable Responses (2017)
  3. RFC 2616 — Hypertext Transfer Protocol — HTTP/1.1 (1999)
  4. MDN Web Docs: Cache-Control
  5. HTTP Archive: State of the Web (статистика использования заголовков кэширования)

BFOmetr — база данных и аналитика по компаниям России.

На главную BFOmetr →