Кеширование по HTTP выглядит как настройка, которую включают один раз и забывают. На деле это договор между сервером и всеми, кто стоит между ним и читателем: браузером, прокси, сетью доставки. Договор либо написан явно, либо каждый участник додумывает его сам — и додумывает по-разному.
Две разные вещи под одним словом
Срок годности. Ответ считается свежим столько-то времени; пока он свежий, за ним вообще не ходят. Это то, что экономит запросы.
Проверка актуальности. Срок вышел, но выбрасывать ответ рано: клиент спрашивает, изменилось ли, и получает короткое «нет». Это экономит трафик, но не запрос.
Разница определяет, что вы получите. Первое убирает обращение целиком, второе оставляет его, но делает дешёвым. Настройка, задающая только второе, ускоряет мало и создаёт ощущение, что кеширование не работает.
Тупик: поставить срок побольше и на всё
Первое, что пробуют, — выставить длинный срок годности для всего подряд. Скорость растёт сразу, и это выглядит успехом.
Это не помогает и создаёт новую проблему: обновление перестаёт доходить. Исправили ошибку в скрипте, выложили — а у части читателей неделю живёт старая версия, и отозвать её нечем. Кеш браузера нельзя очистить с сервера; единственный способ — изменить адрес.
Отсюда правило, из которого следует остальное: длинный срок годности допустим только для того, у чего адрес меняется при изменении содержимого. Файл с хешем в имени — можно. Страница по постоянному адресу — нельзя.
Второй частый ход — отключить кеширование везде, чтобы «не путаться». Тогда каждый заход тянет всё заново, включая то, что не менялось месяцами.
Что чем кешируется
Собранные файлы с хешем в имени. Стили, скрипты, шрифты, картинки, у которых имя меняется при пересборке. Здесь уместен максимальный срок и пометка, что содержимое по этому адресу неизменно: клиент не станет проверять его даже при обновлении страницы.
Страницы. Меняются по редакционным причинам, адрес постоянный. Им нужен нулевой срок с обязательной проверкой: клиент каждый раз спрашивает, изменилось ли, и в ответ обычно получает короткое подтверждение вместо всей страницы.
Данные, которые читают многие и меняют редко. Их полезно разрешить кешировать промежуточным узлам, а не только браузеру, и задать короткий срок.
Личные ответы. Всё, что зависит от того, кто спрашивает, должно кешироваться только в браузере этого человека и никогда — общим узлом. Ошибка здесь дороже любой другой: чужие данные показываются не тому.
Разделение на «только свой браузер» и «можно всем» задаётся явно и по умолчанию работает не так, как ожидают: ответ без указаний промежуточный узел вправе считать общим. Поэтому личное помечают всегда, а не когда вспомнят.
Загрузки и медиа. Крупные файлы, которые не меняются, — самый выгодный случай: длинный срок экономит и трафик, и время. Но если имя файла постоянное, а содержимое иногда подменяют, вы получите худший вариант: часть читателей неделями видит старую версию документа и не знает об этом.
Чем задаётся проверка
Есть два способа подтвердить актуальность, и они не равноценны.
По отпечатку содержимого. Сервер отдаёт короткую строку, вычисленную из ответа; клиент присылает её обратно и получает подтверждение, если ничего не изменилось. Работает точно, но требует, чтобы отпечаток совпадал между перезапусками и серверами. Отпечаток, зависящий от времени сборки или номера узла, ломает кеш при каждой выкатке.
По дате изменения. Проще, но точность до секунды и не различает содержимое: файл, пересобранный без изменений, выглядит новым.
Отпечаток предпочтительнее, если он стабилен. Нестабильный отпечаток хуже даты.
Стабильность проверяется просто: перезапустите сервер и запросите один и тот же файл дважды. Если отпечаток изменился, а содержимое нет, кеш у ваших читателей обнуляется при каждой выкатке — и все настройки сроков не значат ничего.
Где это ломается тише всего
Разные ответы по одному адресу. Сервер отдаёт по-разному в зависимости от языка, сжатия или устройства, но не сообщает об этом. Промежуточный узел закеширует один вариант и раздаст всем. Лечится указанием, от каких признаков зависит ответ, — и указывать надо ровно те, что реально влияют: лишний признак убивает кеш совсем.
Перенаправления. Постоянное перенаправление кешируется агрессивно и живёт в браузере долго. Поставленное по ошибке, оно возвращается к читателю неделями после исправления.
Ошибки. Ответ об ошибке тоже кешируется, если не сказано обратного. Пятиминутный сбой, закешированный на час, превращается в часовой.
Разница между обновлением и заходом заново. Обновление страницы заставляет клиента проверять то, что он считал свежим; обычный переход — нет. Поэтому «у меня всё работает после обновления» ничего не доказывает.
Как проверять
Смотреть надо не на скорость, а на то, что происходит с запросами. В инструментах разработчика видно, какие ответы взяты из кеша, какие подтверждены проверкой, а какие пришли целиком. Три состояния, и путать их не стоит.
Полезно свести это в таблицу один раз: адрес, срок годности, способ проверки, кому разрешено кешировать. Пока такой таблицы нет, настройки живут в нескольких местах — в коде приложения, в конфигурации прокси, в правилах сети доставки — и противоречат друг другу незаметно, потому что побеждает не тот, кто прав, а тот, кто ближе к читателю.
Проверять надо в трёх сценариях: первый заход, повторный переход по сайту и заход после выкатки новой версии. Третий важнее всех: именно там выясняется, что читатели видят старое.
Отдельно стоит проверить, что видит человек, пришедший впервые с другого сайта, — у него нет ничего в кеше, и его опыт определяется размером первой загрузки, а не настройками сроков. Кеширование улучшает второй заход и почти не влияет на первый; если болит именно первый, работать надо с объёмом, а не с заголовками.
Позиция редакции
Мы считаем, что правило одно и простое: длинный срок годности — только адресам, которые меняются вместе с содержимым; всему остальному — обязательная проверка. Практический вывод: если у вас на странице стоит срок больше нуля, вы уже согласились какое-то время показывать читателям устаревшее и не можете это отменить.
Мы неправы, если содержимое по постоянному адресу заведомо не меняется — архивная публикация, снимок отчёта. Там длинный срок уместен и экономит заметно.