Как работает HTTP-кеширование: Cache-Control, ETag и Last-Modified?
HTTP и HTTPS
Cache-Control определяет, сколько ответ свеж и кто может его хранить, а ETag и Last-Modified позволяют дёшево перепроверить устаревшую копию и получить 304 без тела.
Cache-Control
max-age=3600— час без запросов к серверу;s-maxage— то же для общих кешей вроде CDN.no-cache— хранить можно, но перед использованием обязательно перепроверить;no-store— не хранить вовсе.private— только браузер,public— можно и CDN.immutable— не перепроверять даже при перезагрузке;stale-while-revalidate=60— отдать старое и обновить в фоне.
Валидация
- Сервер отдаёт
ETag: "a1b2"илиLast-Modified. - Копия протухла — браузер шлёт
If-None-Match: "a1b2"илиIf-Modified-Since. - Ничего не изменилось —
304 Not Modifiedбез тела, копия снова свежая.
Last-Modified имеет секундную точность, ETag надёжнее. Vary: Accept-Encoding велит хранить отдельный вариант на каждое значение заголовка.
Типовая стратегия
Статике с хешем в имени — год и immutable, HTML — no-cache. На клиенте:
await fetch('/', { cache: 'no-cache' }); // перепроверить по ETag
// 'force-cache' — взять даже устаревшую копию, 'reload' — мимо кеша
let etag, data;
async function load(url) {
const res = await fetch(url, { cache: 'no-store', headers: etag ? { 'If-None-Match': etag } : {} });
if (res.status === 304) return data;
etag = res.headers.get('ETag');
return (data = await res.json());
}
const [e] = performance.getEntriesByName(`${location.origin}/app.3f9c.js`);
console.log(e.transferSize ? 'по сети' : 'из кеша');Коротко для собеседования
Кешем управляют два механизма: свежесть через Cache-Control и дешёвая перепроверка через ETag с ответом 304. Рабочая схема — статике с хешем в имени год и immutable, HTML — no-cache, иначе после деплоя пользователи застрянут на старой версии.