📦 HTTP-заголовки и кэширование
💡 Основная идея
Вся ценность кэширования — в том, чтобы полностью пропустить сетевую цепочку из TCP & TLS Handshake, или хотя бы пропустить самую дорогую её часть — тело ответа.
🏷 Категории заголовков
- General — не привязаны конкретно к запросу или ответу:
Date,Connection(keep-alive),Cache-Control(используется в обоих). - Request — контекст запроса:
Host,User-Agent,Accept,Authorization,If-None-Match. - Response — контекст ответа:
Server,Set-Cookie,Location. - Entity/Representation — описывают тело независимо от направления:
Content-Type,Content-Length,Content-Encoding,ETag,Last-Modified.
Разделение не формальное — это скорее подсказка, где заголовок вообще имеет смысл (Content-Length бессмыслен без тела).
🗄 Cache-Control
max-age=N— сколько секунд ответ считается свежим; в течение этого окна браузер мгновенно отдаёт кэшированную копию, вообще не обращаясь к серверу.no-cache— обманчивое название: кэшировать можно, но при каждой отдаче требуется ревалидация с сервером через условный запрос (см. ETag ниже).no-store— кэширование запрещено полностью, в любой форме.private/public— можно кэшировать только в браузере пользователя / можно кэшировать в любом месте цепочки (включая CDN/прокси).
Ключевое отличие: no-cache = «кэшируй, но всегда ревалидируй»; no-store = «вообще не кэшируй».
ETag и условные запросы
- Первый ответ:
200 OK+ тело +ETag: "abc123"(отпечаток конкретной версии ресурса). - Кэшированная копия устарела /
no-cache— браузер отправляетIf-None-Match: "abc123"вместо слепой повторной загрузки. - Сервер сравнивает: совпадение →
304 Not Modified, без тела (экономит весь трафик, который занимало бы тело ответа); нет совпадения →200 OK+ новое тело + новыйETag.
If-Modified-Since/Last-Modified работают по тому же принципу, но по времени, а не по хешу — грубее (точность до секунды), но не требует вычисления хеша на сервере.
В ответах 304 нет ничего, кроме заголовков — ни тела, ни дополнительной структуры.
Где кэширование находится в цепочке
Кэширование срабатывает до сети: если max-age ещё не истёк, соединение вообще не открывается (ни DNS, ни TCP, ни TLS). no-cache/304 — частичный выигрыш: сам round trip всё равно происходит, но экономится самая дорогая часть (тело ответа).
🌍 Места хранения кэша и стратегии
Три точки на пути запроса, каждая — потенциальный «склад» с готовой копией, от ближайшей/быстрейшей до самой дальней/медленной:
- Кэш браузера — копия на диске/в памяти пользователя. Сеть вообще не задействована.
- CDN — копия на сервере, географически близком к пользователю (не origin-сервер сайта). Требует сети, но путь короче. Используется только если ответ помечен
Cache-Control: public;privateразрешает копию только в кэше браузера, но не на CDN/общем прокси. - Origin-сервер — место, где реально живут код и данные. Самый дальний вариант, к которому обращаются, только если копии взять больше негде.
Стратегии
- cache-first — если что-то есть в кэше, отдать это и вообще не трогать сеть (без проверок, а не «постоянная ревалидация»). Безопасно для ресурсов, которые никогда не меняются под одним и тем же URL (хешированное имя файла — изменение порождает новое имя/URL, поэтому старая закэшированная копия никогда не может стать «неправильной»).
- network-first — сначала пытаться получить свежую копию по сети; кэш — лишь запасной вариант на случай недоступности сети. Для часто меняющихся данных (лента, курс валют), где важна свежесть.
- stale-while-revalidate — гибрид: сразу отдать то, что есть в кэше (даже если оно устарело), и параллельно, в фоне выполнить обычный сетевой запрос, чтобы обновить кэш для следующего раза. Пользователь никогда не ждёт сеть, но не всегда видит самую новую версию.
HTTP & Network TCP & TLS Handshake — что позволяет пропустить кэширование CORS — ещё один сетевой шлюз на стороне браузера browser