Кэш браузера на пять минут: постоянные клиенты качают ваш сайт заново каждый раз

Кэш браузера на пять минут: постоянные клиенты качают ваш сайт заново каждый раз
Анатолий Кузнецов
Анатолий Кузнецов
SEO-оптимизатор с 20-летним стажем. Автор блога seo-prodvizhenie-biznesa.ru о продвижении и доработке сайтов.

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

Это не проблема вёрстки и не повод переделывать сайт. Это несколько строк в конфиге сервера, которые ставятся за полчаса и дальше работают сами. С 2005 года я вижу одну и ту же картину: владелец платит за оптимизацию картинок, за сжатие, за перенос на быстрый хостинг — а заголовки кэширования при этом либо отсутствуют, либо стоят на смешные пять-десять минут, потому что так по умолчанию прописал хостер или так «на всякий случай» решил разработчик.

Разница видна сразу. Первый визит на сайт — браузеру надо скачать всё: HTML, стили, шрифты, скрипты, картинки. Это может быть 60–80 запросов и пара мегабайт. Второй визит при правильных заголовках — браузер берёт почти всё с диска, а с сервера запрашивает только сам HTML. Остаётся один-два запроса вместо восьмидесяти. Страница появляется практически мгновенно, потому что ничего качать не нужно.

Кому это важно: сайтам с повторными визитами. Блог, интернет-магазин, сервис, любой ресурс, куда человек возвращается. Кому почти не важно — разберу отдельно в конце, там есть честный ответ. Если разбираться самому некогда, я делаю это в рамках доработки сайта, а общий разбор технических проблем входит в SEO-продвижение сайта в Яндексе.

Cache-Control: что означает каждая директива

Заголовок Cache-Control — это инструкция сервера браузеру: что делать с этим файлом после того, как он скачан. Сервер отдаёт её вместе с файлом, в HTTP-ответе. Браузер её читает и подчиняется. Никакой магии, никаких настроек на стороне посетителя.

Выглядит это так:

Cache-Control: public, max-age=31536000, immutable

Три части, каждая отвечает за своё. Разберу по элементам, потому что путаница именно здесь: люди ставят no-cache, думая, что запретили кэширование, а на самом деле разрешили — просто с обязательной перепроверкой.

Директива Что реально делает Когда ставить
max-age=N Сколько секунд файл считается свежим. Всё это время браузер берёт его с диска, вообще не обращаясь к серверу Основная директива. 31536000 — год, 2592000 — 30 дней, 3600 — час
public Файл разрешено хранить не только браузеру, но и промежуточным кэшам — прокси, CDN Статика: стили, скрипты, шрифты, картинки
private Хранить может только браузер конкретного посетителя. Промежуточным кэшам запрещено Персональные страницы: корзина, личный кабинет, страница заказа
no-cache Сохранить можно, но перед каждым использованием обязательно спросить сервер: «файл не изменился?» HTML-страницы, которые правятся, но не персональные
no-store Не сохранять вообще нигде, ни на диск, ни в память Только по-настоящему чувствительное: страницы оплаты, ответы с личными данными
immutable Файл не изменится никогда. Браузер не будет перепроверять его даже при нажатии F5 Файлы с хэшем в имени: style.a1b2c3.css
must-revalidate Когда срок вышел — обязательно спросить сервер, нельзя отдавать устаревшую копию Данные, где старая версия хуже, чем ошибка
s-maxage=N Срок отдельно для промежуточных кэшей (CDN), перебивает max-age для них Когда CDN должен держать файл дольше, чем браузер

Главная пара, которую путают: no-cache и no-store. Первое — «храни, но проверяй». Браузер сохранит файл, при следующем открытии отправит короткий условный запрос, получит в ответ 304 Not Modified — и возьмёт копию с диска. Трафика почти ноль, но один сетевой запрос всё равно есть. Второе — «не храни». Каждый раз качать заново, целиком. no-store на статике — это прямой убыток скорости, а стоит он на удивление часто, потому что кто-то однажды решил «отключить кэш, чтобы клиенты видели свежую версию».

И третье значение, про которое забывают: max-age=0. Оно означает «файл протух в момент выдачи» — то есть браузер каждый раз пойдёт перепроверять. По эффекту близко к no-cache, но не идентично.

Expires, ETag, Last-Modified и эвристический кэш

До Cache-Control сроком жизни файла управлял заголовок Expires. Он указывает не длительность, а конкретную дату и время, до которых копия считается свежей:

Expires: Thu, 31 Dec 2026 23:59:59 GMT

Проблема очевидна: дата абсолютная. Она зависит от часов на устройстве посетителя. Если у человека сбиты системные часы — а это встречается чаще, чем кажется, — вся логика ломается: файл либо мгновенно считается протухшим, либо, наоборот, живёт вечно. Плюс дату надо пересчитывать, а max-age просто говорит «год от момента получения», и никакие часы не участвуют.

Поэтому правило простое: если в ответе есть и Cache-Control: max-age, и Expires, браузер слушает Cache-Control, а Expires игнорирует. Держать оба не вредно — старые прокси иногда понимают только второй, — но настраивать надо первый. Модуль Apache mod_expires, несмотря на название, умеет выставлять оба заголовка сразу, и это как раз тот случай, когда название модуля вводит в заблуждение.

ETag и Last-Modified: как проходит перепроверка

Когда срок свежести истёк, браузер не качает файл вслепую. Сначала он спрашивает: «у меня версия такая-то, она ещё актуальна?» Для этого используются два заголовка, которые сервер отдал вместе с файлом.

Last-Modified — дата последнего изменения файла. Браузер при повторном запросе шлёт её обратно в заголовке If-Modified-Since. Если файл с тех пор не менялся, сервер отвечает 304 Not Modified — ответ без тела, несколько сотен байт. Браузер берёт копию с диска.

ETag — метка версии файла, обычно хэш от содержимого или связка «размер + время изменения». Браузер шлёт её обратно в If-None-Match. Тот же результат: 304 вместо полной перекачки.

Оба механизма экономят трафик, но не экономят время на установление соединения и ожидание ответа сервера. На мобильном интернете один такой запрос — это 100–300 мс, и если их сорок, набегает больше секунды до отрисовки. Поэтому 304 — это хорошо, но from disk cache без единого запроса — гораздо лучше. Задача настройки в том, чтобы статика вообще не доходила до перепроверки.

Отдельная тонкость с ETag на нескольких серверах: если сайт стоит за балансировщиком и файл лежит на двух машинах, Apache по умолчанию генерирует разные ETag для одного и того же файла (в расчёт входит inode). Браузер получает метку с одного сервера, приходит на другой — метки не совпадают, файл качается заново. Лечится директивой FileETag MTime Size или полным отключением ETag там, где хватает Last-Modified.

Эвристическое кэширование: когда заголовков нет вообще

Если сервер не прислал ни Cache-Control, ни Expires, браузер не выбрасывает файл — он придумывает срок сам. Это и есть эвристическое кэширование. Распространённая формула: взять разницу между текущим временем и Last-Modified и закэшировать примерно на 10% от неё. Файл, изменённый год назад, проживёт в кэше около месяца. Файл, изменённый вчера, — пару часов.

Проблема эвристики в том, что она неуправляема. Вы не знаете, что решит конкретный браузер конкретной версии, и не можете на это влиять. Один посетитель получит месяц, другой — час. Диагностировать «почему у клиента старые стили» в такой ситуации невозможно: поведение зависит от даты файла на сервере, которая меняется при каждом деплое. Явные заголовки нужны в том числе ради предсказуемости, а не только ради скорости.

Сколько кэшировать каждый тип ресурса

Универсального числа нет, но есть логика: срок кэширования обратно пропорционален частоте изменений и прямо пропорционален тому, насколько легко вы можете принудительно обновить файл. Если у файла в имени есть версия — кэшируйте на год, менять вы будете не файл, а ссылку на него. Если имя постоянное — ставьте срок, который готовы ждать.

Тип ресурса Разумный срок Почему именно так
HTML-страницы Не кэшировать или no-cache Контент меняется, цены меняются, товар кончается. Посетитель не должен видеть вчерашнюю страницу. Условный запрос с 304 дешёвый, им и обходимся
CSS и JS с хэшем в имени 1 год, immutable Файл app.7f3c9d.js по определению не изменится: изменится содержимое — изменится имя. Перепроверять нечего
CSS и JS без версии в имени 7–30 дней Компромисс. Меньше — теряете смысл кэша, больше — при правке дизайна часть аудитории неделями видит старое
Шрифты (woff2) 1 год, immutable Шрифты не меняются никогда. Это самый тяжёлый и самый статичный тип файла на сайте
Картинки контента 30–180 дней Фото товара и иллюстрации в статьях живут долго. При замене обычно меняется и имя файла
Картинки интерфейса (логотип, иконки, спрайты) 6–12 месяцев Логотип переделывают раз в несколько лет. Держать его на неделе — бессмысленно
favicon.ico 7–30 дней Исключение из логики картинок: браузеры кэшируют фавикон крайне упорно, а сбросить его версией через ?v= получается не всегда. Длинный срок здесь мешает больше, чем помогает
PDF, документы, архивы 30 дней Меняются редко, но иногда меняются — прайс-лист, каталог
Ответы API, JSON с данными 0–300 секунд Зависит от данных. Остатки на складе — секунды. Список городов доставки — часы
Личный кабинет, корзина private, no-store Чужие данные в общем кэше — это утечка, а не оптимизация

Год — не преувеличение. Это верхняя граница, которую понимают все браузеры: 31536000 секунд. Указывать больше бессмысленно, спецификация ограничивает срок примерно годом. И год — это ровно то, что советует Google PageSpeed в пункте «Используйте эффективную политику кэширования», который на большинстве сайтов горит красным именно из-за пятиминутных заголовков. Как этот пункт связан с реальными метриками загрузки, я подробно разбирал в материале о том, какая метрика скорости на самом деле решает позиции.

«Поменял стили — а клиенты видят старое»: версионирование

Это главный страх, из-за которого длинные сроки не ставят. Логика владельца понятна: если файл закэширован на год, а я правлю дизайн — постоянные посетители будут месяцами видеть старую вёрстку. Страх обоснованный, но решается он не уменьшением срока, а сменой имени файла.

Механика простая. Браузер кэширует не «файл стилей», а конкретный URL. /css/style.css и /css/style.css?v=12 — для кэша два разных адреса. Меняете версию в ссылке — браузер считает, что это новый ресурс, которого у него нет, и качает его. Все остальные файлы при этом остаются в кэше нетронутыми.

Два рабочих подхода:

  • Параметр запроса: <link rel="stylesheet" href="/css/style.css?v=1.4.2">. Проще всего, работает везде. В WordPress это делается штатно — третьим аргументом wp_enqueue_style(), куда стоит подставлять не константу, а время изменения файла: filemtime(). Тогда версия обновляется сама при каждой правке. Минус: некоторые старые прокси и CDN игнорируют строку запроса при кэшировании.
  • Хэш в имени файла: /css/style.a1b2c3d4.css. Файл физически называется по-другому, путаницы не бывает нигде. Так работают сборщики — Webpack, Vite, Gulp. Именно для таких файлов существует immutable: адрес гарантированно уникален для содержимого, перепроверять нечего.

Чего делать нельзя: полагаться на то, что посетитель нажмёт Ctrl+F5. Он не нажмёт. Он не знает, что такое кэш, и не должен знать. Инструкции вида «очистите кэш браузера» на сайте — это признание, что версионирование не настроено. То же касается писем клиентам с просьбой обновить страницу: доходят такие письма до единиц, а видят старую версию все.

Отдельно про WordPress: там принято, что тема и плагины подключают свои файлы через wp_enqueue_style и wp_enqueue_script с версией. Если разработчик темы поленился и версия жёстко зашита как '1.0', то при правке style.css ссылка не изменится — и вот тогда посетители действительно застревают на старом. Проверяется за секунду: откройте исходный код страницы и посмотрите, есть ли ?ver= у ваших стилей и меняется ли значение после правки. Похожая путаница возникает и с серверным кэшем — про неё есть отдельный разбор, почему после правок вы видите старую страницу, а робот — новую.

Настройка на Apache, nginx и в WordPress

Дальше зависит от того, что у вас за сервер. На типичном виртуальном хостинге это Apache и файл .htaccess в корне сайта. На VPS с nginx — конфиг виртуального хоста. На связке nginx+Apache статику обычно отдаёт nginx напрямую, минуя Apache, — и тогда правки в .htaccess просто не действуют на картинки и стили. Это частая ловушка: настроил, проверил через curl, ничего не изменилось, потому что до Apache запрос не доходит.

Apache: .htaccess

Нужны два модуля: mod_expires и mod_headers. На нормальном хостинге они включены, на дешёвом бывает, что нет — тогда конструкции <IfModule> просто молча ничего не сделают.

<IfModule mod_expires.c>
  ExpiresActive On
  ExpiresDefault "access plus 1 month"

  ExpiresByType text/html "access plus 0 seconds"
  ExpiresByType text/css "access plus 1 year"
  ExpiresByType application/javascript "access plus 1 year"
  ExpiresByType font/woff2 "access plus 1 year"
  ExpiresByType image/jpeg "access plus 6 months"
  ExpiresByType image/png "access plus 6 months"
  ExpiresByType image/webp "access plus 6 months"
  ExpiresByType image/svg+xml "access plus 6 months"
  ExpiresByType image/x-icon "access plus 1 week"
</IfModule>

<IfModule mod_headers.c>
  <FilesMatch "\.(css|js|woff2|jpg|jpeg|png|webp|svg)$">
    Header set Cache-Control "public, max-age=31536000"
  </FilesMatch>
  <FilesMatch "\.(html|php)$">
    Header set Cache-Control "no-cache, must-revalidate"
  </FilesMatch>
</IfModule>

Важный момент: ExpiresByType работает по MIME-типу, который сервер сам определяет по расширению. Если сервер отдаёт woff2 как application/octet-stream, правило для font/woff2 не сработает. Проверяется тем же curl -I — смотрите строку Content-Type.

nginx

Здесь всё компактнее. Директива expires сама выставляет и Expires, и Cache-Control: max-age:

location ~* \.(css|js)$ {
    expires 1y;
    add_header Cache-Control "public, immutable";
    access_log off;
}

location ~* \.(jpg|jpeg|png|webp|gif|svg|ico)$ {
    expires 6M;
    add_header Cache-Control "public";
}

location ~* \.(woff2|woff|ttf)$ {
    expires 1y;
    add_header Cache-Control "public, immutable";
}

location / {
    expires -1;
    add_header Cache-Control "no-cache, must-revalidate";
}

Две ловушки nginx, на которые я натыкался не раз. Первая: add_header наследуется в дочерний блок только если в самом дочернем блоке нет ни одного своего add_header. Добавили в location заголовок безопасности — и все унаследованные заголовки кэширования исчезли. Вторая: если вы правите конфиг руками, а сервером управляет панель (ISPmanager, cPanel), панель при следующем изменении настроек сайта перезапишет файл и ваши правки исчезнут. Класть такие вещи надо в подключаемый файл, который панель не трогает, и обязательно проверять после каждого изменения настроек хостинга.

Плагины WordPress: что они делают на самом деле

Кэш-плагины — W3 Total Cache, WP Rocket, LiteSpeed Cache, WP Super Cache — почти все умеют «включить кэш браузера». Технически это означает ровно одно: плагин дописывает блок с ExpiresByType и Header set Cache-Control в ваш .htaccess. Никакой отдельной магии там нет, и на nginx без Apache эта галочка не делает вообще ничего — плагин пишет в файл, который сервер не читает.

Что из этого следует практически: если у вас nginx, галочку в плагине можно не искать, настраивать надо конфиг. Если Apache — галочку включить можно, но потом стоит открыть .htaccess и посмотреть, какие сроки плагин прописал. Часто это те самые скромные значения вроде часа или суток. И помните, что .htaccess — общий файл: плагин пишет свой блок туда же, где лежат ваши редиректы, и порядок блоков иногда имеет значение. Про то, что ещё живёт в этом файле и как не сломать его правкой, есть смысл читать вместе с материалом о настройке 301-редиректов без плагина.

Как проверить, что кэш работает

Проверка занимает две минуты и не требует никаких сервисов. Три способа, от самого наглядного к самому точному.

Вкладка Network в браузере. Откройте инструменты разработчика (F12), вкладку Network, загрузите страницу. Затем — не закрывая панель — перейдите на другую страницу сайта и вернитесь, или просто откройте сайт заново. Смотрите колонку Size. Значения (disk cache) или (memory cache) означают, что файл взят локально, запроса к серверу не было. Цифра в килобайтах означает, что файл скачан заново. Строка со статусом 304 означает, что был запрос-перепроверка: трафика почти нет, но время на запрос потрачено.

Одна деталь, из-за которой проверка часто врёт: галочка «Disable cache» в панели разработчика. Если она стоит, браузер игнорирует все заголовки и качает всё заново. Снимите её перед проверкой. И не проверяйте через Ctrl+F5 — это принудительная перезагрузка с обходом кэша, она покажет вам ровно то, чего вы не хотите видеть. Проверять надо обычным переходом по ссылке.

Запрос через curl. Самый честный способ: он показывает сырые заголовки, без участия браузера.

curl -I https://example.ru/wp-content/themes/mytheme/style.css

В ответе ищите строки Cache-Control, Expires, ETag, Last-Modified. Если Cache-Control нет вовсе — заголовки не настроены и работает эвристика. Если там max-age=300 — вот они, ваши пять минут.

PageSpeed Insights. Пункт «Serve static assets with an efficient cache policy» / «Используйте эффективную политику кэширования» перечисляет конкретные файлы с их сроками. Это удобный список того, что чинить, но по нему нельзя судить о скорости сайта в целом — он не учитывает, есть ли у вас вообще повторные визиты. Полную картину даёт связка Вебмастера, реальных метрик Core Web Vitals и логов сервера: в логах видно, сколько запросов к статике вы реально обслуживаете и сколько из них отвечают 304.

Кэш браузера, кэш страниц и CDN — три разные вещи

В разговорах их постоянно смешивают, и из-за этого возникают диалоги вроде «я же сбросил кэш, почему не обновилось». Сбросил — какой из трёх? Они находятся в разных местах и сбрасываются по-разному.

Признак Кэш браузера Серверный кэш страниц CDN
Где физически лежит На диске устройства посетителя На вашем сервере — файлы или память На узлах сети, географически ближе к посетителю
Что хранит Скачанные файлы: стили, скрипты, картинки, шрифты Готовый HTML страницы, чтобы не собирать её из базы заново Копии статики, иногда и HTML
Кому помогает Только повторным посетителям Всем, включая первый визит Всем, особенно из других регионов
Что ускоряет Отрисовку при повторном визите — файлы не качаются Время ответа сервера, TTFB Сетевую задержку до файла
Как сбросить Никак напрямую. Только сменой URL файла (версия или хэш) Кнопка «очистить кэш» в плагине или на сервере Purge в панели CDN
Помогает ли роботу Практически нет — робот приходит «чистым» Да, робот получает быстрый ответ Да

Последняя строка важна для понимания того, зачем всё это в SEO. Поисковый робот кэш браузера почти не использует — он каждый раз запрашивает ресурсы заново. Значит, длинные заголовки кэширования сами по себе позиции не двигают. Двигают их два косвенных эффекта: улучшение поведенческих у вернувшихся посетителей (страница открывается мгновенно, человек не уходит) и разгрузка сервера — меньше запросов к статике означает больше ресурсов на выдачу HTML роботу и живым людям. Если сервер отвечает медленно, кэш браузера эту проблему не решит вообще: секунда до первого байта лечится другими средствами.

И ещё одна путаница, которую стоит развести: Cache-Control и время жизни серверного кэша страниц никак не связаны. Можно отдавать HTML с no-cache для браузера и при этом держать его в серверном кэше час. Это нормальная и правильная конфигурация.

Когда это не нужно и не сработает

Честный список ситуаций, где настройка заголовков даст мало или ничего.

Трафик из контекстной рекламы, где повторных визитов почти нет. Посадочная страница под объявление, человек пришёл, оставил заявку или ушёл, второй раз не возвращается. Кэш браузера помогает только со второго визита — при доле повторных посетителей в 5% выгода будет пропорциональной. Смотреть надо в Метрику: отчёт по новым и вернувшимся посетителям даёт точный ответ за минуту. Если вернувшихся мало, силы лучше вложить в скорость первого визита — вес картинок, количество запросов, время ответа сервера.

Сайт из трёх лёгких страниц. Если вся статика весит 200 килобайт, экономить на повторной загрузке нечего. Эффект будет, но незаметный.

Сервер отвечает за две секунды. Кэш браузера не ускоряет ответ сервера. Он вообще не влияет на HTML — HTML вы кэшировать не будете. Пока TTFB высокий, все остальные оптимизации теряются на его фоне. Сначала сервер, потом всё остальное — то же касается ситуации, когда сайт собран на тяжёлом конструкторе и грузится шесть секунд из-за самого билдера.

Файлы подключены без версий, а сайт правится ежедневно. Ставить год на style.css без версионирования — гарантированная беда. Сначала настройте версии, потом сроки. В обратном порядке — не надо.

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

Ожидание, что позиции вырастут напрямую. Не вырастут. Это гигиена и удобство для людей, а не рычаг ранжирования. Влияние на выдачу — только косвенное, через поведение и через нагрузку. Гораздо сильнее на скорость влияют вес и формат картинок, и начинать я обычно советую именно с них.

Коротко

  • Кэш браузера настраивается заголовками HTTP-ответа. Главный — Cache-Control, в нём max-age задаёт срок в секундах.
  • no-cache — «храни, но перепроверяй». no-store — «не храни». Их постоянно путают, и вторым режут скорость на статике.
  • Expires — устаревший заголовок с абсолютной датой, зависящей от часов посетителя. При конфликте побеждает Cache-Control.
  • ETag и Last-Modified дают экономию трафика через ответ 304, но не экономят время запроса. Цель — вообще не доходить до перепроверки.
  • Без заголовков браузер применяет эвристику и придумывает срок сам. Результат непредсказуем.
  • Сроки: HTML — не кэшировать, шрифты и версионированные CSS/JS — год с immutable, картинки — месяцы, favicon — неделя-месяц.
  • Проблема «клиенты видят старые стили» решается версией в URL (?v= или хэш в имени), а не коротким сроком и не просьбой очистить кэш.
  • Apache — mod_expires и mod_headers в .htaccess. nginx — expires и add_header. Плагины WordPress просто пишут в .htaccess и на чистом nginx бесполезны.
  • Проверка: вкладка Network со снятой галочкой «Disable cache», колонка Size со значением from disk cache, и curl -I для сырых заголовков.
  • Кэш браузера, серверный кэш страниц и CDN — три разных механизма в трёх разных местах. Роботу помогают второй и третий, посетителю — все.

Чеклист по кэшу браузера

Пройдите по списку сверху вниз. Порядок не случайный: пункты 1–3 надо закрыть до того, как трогать сроки.

Что проверить Как проверить Норма
1 Есть ли повторные визиты вообще Метрика, отчёт «Новые и вернувшиеся посетители» Доля вернувшихся выше 15–20% — настройка окупается
2 У стилей и скриптов есть версия в URL Исходный код страницы, искать ?ver= или хэш в имени Версия есть и меняется после правки файла
3 Кто отдаёт статику — Apache или nginx curl -I, заголовок Server; конфиг хостинга Знаете точно, куда писать настройки
4 Заголовок Cache-Control на CSS и JS curl -I по адресу файла стилей public, max-age=31536000 при версионировании
5 Заголовок на шрифтах curl -I по адресу woff2 public, max-age=31536000, immutable
6 Заголовок на картинках curl -I по логотипу и по фото из контента public, срок от месяца
7 HTML не кэшируется надолго curl -I по адресу главной no-cache или max-age=0
8 Личный кабинет и корзина не в общем кэше curl -I по адресу корзины Есть private или no-store, нет public
9 Нигде не стоит no-store на статике Поиск по .htaccess и конфигу nginx На CSS, JS, картинках и шрифтах no-store отсутствует
10 Повторная загрузка берёт файлы с диска Network, обычный переход, галочка Disable cache снята Большинство статики — (disk cache), а не 304 и не килобайты
11 ETag одинаковый на всех серверах Актуально при балансировке: curl -I несколько раз Метка совпадает; иначе FileETag MTime Size
12 Настройки пережили обновление панели Повторный curl -I через неделю и после правок в панели хостинга Заголовки на месте, конфиг не перезаписан

Двенадцать пунктов — это примерно час работы вместе с проверками, и дальше настройка живёт сама. Единственное, за чем стоит присматривать, — пункт 12: панели управления хостингом любят возвращать свои конфиги после обновлений, и заголовки тихо пропадают. Если хочется получить список конкретных технических проблем именно по вашему сайту, включая кэширование, — это бесплатный аудит сайта, по нему обычно и становится понятно, с чего начинать.

Увеличьте позиции и продажи вашего сайта

Профессиональное SEO-продвижение с гарантией результата. Выберите подходящую услугу:

Анатолий Кузнецов — SEO-оптимизатор

Остались вопросы по продвижению?

Меня зовут Анатолий Кузнецов, я SEO-оптимизатор с 20-летним стажем. Разберу ваш сайт, отвечу на вопросы и подскажу, что улучшить для роста позиций в Яндексе и Google.

Связаться со мной →

Комментарии

Игорь

Проверил через curl свой интернет-магазин — на всех картинках нет Cache-Control, только Last-Modified. То есть у меня всё это время работала эвристика, о которой я даже не подозревал. Прописал явные сроки, теперь хотя бы понимаю, что происходит у посетителя.

Марина

Спасибо, наконец поняла разницу между no-cache и no-store. У нас разработчик поставил no-store на всё подряд «чтобы точно обновлялось». Теперь понятно, почему сайт для постоянных клиентов такой медленный.

Дмитрий В.

Не согласен насчёт года на CSS. У нас сайт правится каждую неделю, и я не готов рисковать. Месяц — потолок, а лучше неделя.

Анатолий Кузнецов автор

Ваша осторожность оправдана ровно до тех пор, пока у файла нет версии в URL. Как только в ссылке появляется ?v= или хэш, риска не остаётся физически: после правки браузер видит новый адрес и качает заново, старая копия просто перестаёт использоваться. Год без версионирования — да, плохая идея. Год с версионированием — безопаснее недели, потому что не зависит от того, когда у кого протухнет.

Алексей

У меня nginx перед Apache. Прописал всё в .htaccess, curl показывает старые заголовки. Долго не мог понять, в чём дело, пока не дочитал до абзаца про то, что статику отдаёт nginx мимо Apache. Перенёс в конфиг — заработало.

Светлана

А фавикон правда так сложно обновить? У нас логотип поменяли полгода назад, а у части сотрудников в закладках до сих пор старая иконка.

Анатолий Кузнецов автор

Да, фавикон — самый упрямый файл. Браузеры хранят его отдельно от обычного кэша страниц и не всегда реагируют на параметр в URL. Работающий способ — сменить само имя файла и путь в теге link, а не добавлять ?v=. И заранее не ставить на него год: неделя-месяц вполне достаточно.

Роман

Правильно понимаю, что для робота Яндекса всё это бесполезно и делается только ради людей?

Анатолий Кузнецов автор

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

Наталья П.

В PageSpeed красный пункт про политику кэширования висит уже год. Плагин кэша стоит, галочка «кэш браузера» включена. Что не так?

Анатолий Кузнецов автор

Два самых вероятных варианта. Первый: у вас nginx, и плагин пишет в .htaccess, который сервер не читает. Второй: плагин прописал короткие сроки, вроде суток, и PageSpeed их не устраивает. Откройте .htaccess и посмотрите, что там реально написано, а потом сверьте с curl -I по конкретному файлу стилей — за пять минут станет ясно, какой из двух случаев.

Виктор

Добавлю от себя: очень выручает filemtime() в третьем аргументе wp_enqueue_style. Версия обновляется сама при сохранении файла, и про кэш можно забыть навсегда.

Егор

Немного запутался с колонкой Size. Что лучше — 304 или disk cache? Мне казалось, 304 это уже хорошо.

Оксана

У нас лендинги под контекст, повторных визитов процентов пять. Получается, тратить время на это не стоит?

Павел С.

Столкнулся с тем, о чём написано про add_header в nginx. Добавили в location заголовок безопасности — и Cache-Control из родительского блока исчез. Искали причину два дня. Спасибо, что упомянули, теперь хотя бы знаю, что это известное поведение, а не наш кривой конфиг.

Тимур

А immutable вообще все браузеры понимают? Не получится, что часть посетителей всё равно будет перепроверять файл?

Анатолий Кузнецов автор

Не все и не одинаково, но это безопасная директива: браузер, который её не понимает, просто её игнорирует и работает по max-age. Хуже не станет ни в каком случае. Основной выигрыш от immutable — при нажатии F5: без неё браузер перепроверяет файлы даже внутри срока свежести, с ней — нет.

Прокрутить вверх