Заголовки кэширования HTTP Cache-Control, ETag и max-age без предположений

Обновлено

Практическое руководство по заголовкам кэширования HTTP для разработчиков веб-сайтов: что на самом деле делают директивы Cache-Control, как ETags инициируют повторную проверку 304, как выбирать TTL, которые выдерживают развертывания, и ошибки, которые делают кэширование вредным, а не полезным.

Заголовки кэширования HTTP: Cache-Control, ETag и max-age Без предположений 1
Реклама · УДАЛИТЬ?

Каждый HTTP-ответ, который вы отправляете, либо кэшируется, либо не кэшируется — и если вы не проявляете осознанности в этом вопросе, то браузер сам решает за вас. В результате обычно наблюдается смешанный подход: агрессивное кэширование для часто меняющихся ресурсов и полное отсутствие кэширования для редко меняющихся. Оба варианта вредят вашим пользователям.

Этот гайд даёт вам модель мышления, чтобы правильно настроить HTTP-заголовки кэширования в первый раз: что каждый директивный элемент управляет, как ETags инициируют перепроверку, и как выбрать TTL, которые выдерживают деплои без предоставления устаревшего контента.

Как работает кэширование в браузере

Когда браузер запрашивает ресурс, он сначала проверяет свой локальный кэш. Если в нём есть свежий кэшированный копии, он немедленно его предоставляет — без каких-либо сетевых запросов. Если кэшированная копия может быть устаревшей, браузер отправляет условный запрос на источник. Источник либо подтверждает, что ресурс не изменился (304 Not Modified), либо отправляет полный обновлённый ответ (200 OK).

CDN находятся в середине этого жизненного цикла. Они кэшируют ответы ближе к пользователям географически, и они соблюдают те же HTTP-заголовки кэширования — с несколькими CDN-специфичными расширениями, такими как s-maxage.

Три вопроса определяют поведение кэширования:

  • Может ли этот ответ быть кэширован вообще? Управляемый Cache-Control: no-store или private
  • На сколько времени он свежий? Управляемый max-age или s-maxage
  • Как проверяется устаревание? Управляемый ETags или Last-Modified

заголовки директивы Cache-Control

The Cache-Control заголовок является основным способом объявления политики кэширования. Множество директив разделяются запятыми. Вот что делает каждая из них:

max-age

max-age=N показывает кэшам (браузеру и CDN), на сколько секунд ответ остаётся свежим. Ответ с max-age=86400 считается свежим ровно в течение 24 часов с момента получения. После этого кэш должен перепроверить его перед тем, как снова его предоставить.

Для статических ресурсов с версионными именами файлов (например, main.abc123.js), годовой срок является распространённым: max-age=31536000. Для HTML-документов гораздо более короткий интервал — или вообще отсутствие кэширования — является более безопасным, поскольку HTML ссылается на эти версионные ресурсы.

s-maxage

s-maxage переопределяет max-age только для общих кэшей (CDN, прокси-серверы). Браузер игнорирует это. Это позволяет предоставлять пользователям долговременные кэшированные ответы, при этом сохраняя более свежие кэши на уровне CDN. Типичная схема — браузер кэширует на 1 час, а CDN — на 24 часа. Cache-Control: public, max-age=3600, s-maxage=86400 — браузер кэширует на 1 час, CDN кэширует на 24 часа.

no-cache

no-cache означает не «не кэшировать». Оно означает, что кэш должен перепроверить с источником перед предоставлением сохранённого ответа, даже если он ещё свеж. Ответ кэшируется, но каждый запрос требует одного круга для проверки его актуальности. Это подходит для контента, который часто меняется, но при этом получает выгоду от экономии пропускной способности за счёт ответа 304.

no-store

no-store является единственным директивным элементом, который фактически запрещает кэширование. Ни браузерный кэш, ни CDN, ни запись на диск. Используйте его для ответов, содержащих чувствительные данные пользователей — банковские выписки, медицинские записи, токены. Не используйте его по умолчанию, если вы не продумали вопрос кэширования ещё.

public и private

public является явным разрешением на кэширование в общих кэшах (CDN), даже если запрос имел Authorization заголовке. private ограничивает кэширование только для браузера пользователя — CDN не должны кэшировать его. Для аутентифицированных ответов, которые являются пользовательскими, private предотвращает то, что ответ одного пользователя будет предоставлен другому.

must-revalidate

must-revalidate предотвращает кэшированные ответы от предоставления устаревших данных, когда они не могут достичь источника. Без этого кэш может предоставить устаревший ответ, если сеть недоступна. С этим кэш не может предоставить ответ, если источник недоступен, и возвращает ошибку 504. Используйте это для контента, где предоставление устаревших данных хуже, чем ошибка.

ETags: точная перепроверка

ETag — это идентификатор, сгенерированный сервером для конкретной версии ресурса — можно представить это как отпечаток для тела ответа. Сервер отправляет его в ответ:

ETag: "abc123def456"

Когда кэшированная копия истекает, браузер отправляет условный GET с сохранённым ETag:

If-None-Match: "abc123def456"

Если ресурс не изменился, сервер отвечает с 304 Not Modified и пустым телом — экономя пропускную способность, при этом подтверждая свежесть. Если ресурс изменился, сервер отвечает с 200 OK и новым ETag.

Сильные и слабые ETags

А сильный ETag ("abc123") означает, что ответ идентичен по байтам. Сильный слабый ETag (W/"abc123") означает, что ответы семантически эквивалентны, но могут отличаться в мелких деталях, таких как пробелы или порядок заголовков. Слабые ETags могут генерироваться более эффективно, но не могут использоваться в запросах на диапазоны. Если у вас нет специфических причин для использования слабых ETags, используйте сильные.

Last-Modified: более старший аналог

Перед ETags серверы использовали Last-Modified временные метки для перепроверки. Сервер отправляет:

Last-Modified: Thu, 01 May 2026 12:00:00 GMT

Браузер перепроверяет с помощью:

If-Modified-Since: Thu, 01 May 2026 12:00:00 GMT

Сервер возвращает 304, если ресурс не изменился с того момента, как была отправлена метка.

Недостаток: временные метки имеют разрешение в одну секунду. Файл, изменённый дважды в той же секунде, будет восприниматься как неизменённый. ETags решают эту проблему и являются предпочтительными. Большинство современных фреймворков отправляют оба — браузер использует тот, который доступен, с предпочтением ETags.

Кэширование без нарушения деплоев

Длительный max-age на статическом ресурсе безопасен только в том случае, если URL меняется при изменении содержимого. Существуют два подхода:

Финишинг URL (рекомендуемый)

Включите хэш содержимого файла в имя файла: main.a1b2c3d4.js. Когда файл изменяется, хэш меняется, URL меняется, и браузер получает новый файл — полностью обходя кэш. Устаревший URL остаётся в кэше, но больше не запрашивается, когда HTML ссылается на новый URL.

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

Добавление версии в URL как параметра запроса (

) технически создаёт другой URL, но некоторые CDN и прокси-серверы игнорируют параметры запроса при формировании ключей кэширования. Финишинг URL в пути является более надёжным и универсально поддерживаемым.main.js?v=1.2.3Общие ошибки, вредящие кэшированию

Кэширование ответов API, которые не должны кэшироваться

JSON-API, возвращающие данные, специфичные для пользователя или зависящие от времени, должны использовать

или как минимум Cache-Control: no-store . Общая ошибка — позволить CDN кэшировать ответ вроде private, no-cacheи предоставлять данные одного пользователя другому. Если ваш API не устанавливает заголовок /api/user/profile , некоторые CDN всё равно кэшируют его, используя гипотезы. Cache-Control Забывание о Vary: Accept-Encoding

Если ваш сервер предоставляет как сжатые, так и несжатые версии ресурса в зависимости от заголовка клиента

, кэш должен хранить отдельные копии для каждого варианта. Без Accept-Encoding , CDN может кэшировать версию gzip и предоставлять её клиенту, который не поддерживает gzip — или наоборот. Всегда устанавливайте его при условном сжатии. Vary: Accept-EncodingИспользование no-cache, когда вы имели в виду no-store

Разработчики часто пишут

когда они хотят полностью запретить кэширование, но Cache-Control: no-cache ещё хранит ответ — он просто требует перепроверки перед каждым использованием. Используйте no-cache когда вы действительно не хотите, чтобы ответ сохранялся в любом месте. no-store Установка max-age на HTML без стратегии кэширования

HTML-документы ссылается на версионные ресурсы. Если вы кэшируете свой HTML с длинным

, пользователи не получат новые имена файлов после деплоя — они будут продолжать работать с старым HTML, который ссылается на старые хэши. Установите короткий TTL (или max-age) на HTML, и оставьте длинные TTL для неизменяемых ресурсов, на которые ссылается HTML. no-cacheРассчитывайте срок действия до запуска

Выбор значения

проще, когда вы можете визуализировать, что это означает в реальном времени. Значение max-age на iotools.cloud позволяет ввести TTL в секундах и увидеть точную дату истечения срока. Полезно для проверки значений, таких как 86400 (24 часа), 2592000 (30 дней) или 31536000 (1 год), до того, как внести их в конфигурацию сервера или правила CDN. Калькулятор TTL / max-age HTTP-кэша Практический чек-лист политики кэширования

HTML-документы:

  • — всегда перепроверяются, пользуются 304 при отсутствии изменений Cache-Control: no-cache Версионные статические ресурсы (JS, CSS, изображения с хэшем в имени файла):
  • Не версионные статические ресурсы (шрифты, иконки): Cache-Control: public, max-age=31536000, immutable
  • (1 неделя) Cache-Control: public, max-age=604800 Ответы API (общие, временные):
  • — короткий TTL в браузере, более длинный TTL в CDN Cache-Control: public, max-age=60, s-maxage=300 Ответы API (пользовательские):
  • Чувствительные данные: Cache-Control: private, no-cache
  • Всегда устанавливайте Cache-Control: no-store
  • при предоставлении сжатых ответов при условном сжатии Vary: Accept-Encoding ETags должны быть включены по умолчанию для любого ресурса, который вы кэшируете — они являются механизмом, обеспечивающим эффективное использование пропускной способности при перепроверке. Большинство веб-серверов (Nginx, Apache, Caddy) генерируют ETags автоматически, если вы не отключили их.

ETags должны быть включены по умолчанию для всех кэшируемых объектов — они обеспечивают эффективное использование пропускной способности при повторной проверке. Большинство веб-серверов (Nginx, Apache, Caddy) генерируют ETags автоматически, если вы не отключили их.

Хотите убрать рекламу? Откажитесь от рекламы сегодня

Установите наши расширения

Добавьте инструменты ввода-вывода в свой любимый браузер для мгновенного доступа и более быстрого поиска

в Расширение Chrome в Расширение края в Расширение Firefox в Расширение Opera

Табло результатов прибыло!

Табло результатов — это интересный способ следить за вашими играми, все данные хранятся в вашем браузере. Скоро появятся новые функции!

Реклама · УДАЛИТЬ?
Реклама · УДАЛИТЬ?
Реклама · УДАЛИТЬ?

новости с техническими моментами

Примите участие

Помогите нам продолжать предоставлять ценные бесплатные инструменты

Купи мне кофе
Реклама · УДАЛИТЬ?