Webrium
Подписаться

Кеширование по HTTP: заголовки, которые действительно работают

Срок годности и проверка — разные механизмы, и путают их чаще всего

Ответ из кеша совпадает с источником или разошёлся с нимсовпалоустарело

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

Две разные вещи под одним словом

Срок годности. Ответ считается свежим столько-то времени; пока он свежий, за ним вообще не ходят. Это то, что экономит запросы.

Проверка актуальности. Срок вышел, но выбрасывать ответ рано: клиент спрашивает, изменилось ли, и получает короткое «нет». Это экономит трафик, но не запрос.

Разница определяет, что вы получите. Первое убирает обращение целиком, второе оставляет его, но делает дешёвым. Настройка, задающая только второе, ускоряет мало и создаёт ощущение, что кеширование не работает.

Тупик: поставить срок побольше и на всё

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

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

Отсюда правило, из которого следует остальное: длинный срок годности допустим только для того, у чего адрес меняется при изменении содержимого. Файл с хешем в имени — можно. Страница по постоянному адресу — нельзя.

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

Что чем кешируется

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

Страницы. Меняются по редакционным причинам, адрес постоянный. Им нужен нулевой срок с обязательной проверкой: клиент каждый раз спрашивает, изменилось ли, и в ответ обычно получает короткое подтверждение вместо всей страницы.

Данные, которые читают многие и меняют редко. Их полезно разрешить кешировать промежуточным узлам, а не только браузеру, и задать короткий срок.

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

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

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

Чем задаётся проверка

Есть два способа подтвердить актуальность, и они не равноценны.

По отпечатку содержимого. Сервер отдаёт короткую строку, вычисленную из ответа; клиент присылает её обратно и получает подтверждение, если ничего не изменилось. Работает точно, но требует, чтобы отпечаток совпадал между перезапусками и серверами. Отпечаток, зависящий от времени сборки или номера узла, ломает кеш при каждой выкатке.

По дате изменения. Проще, но точность до секунды и не различает содержимое: файл, пересобранный без изменений, выглядит новым.

Отпечаток предпочтительнее, если он стабилен. Нестабильный отпечаток хуже даты.

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

Где это ломается тише всего

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

Перенаправления. Постоянное перенаправление кешируется агрессивно и живёт в браузере долго. Поставленное по ошибке, оно возвращается к читателю неделями после исправления.

Ошибки. Ответ об ошибке тоже кешируется, если не сказано обратного. Пятиминутный сбой, закешированный на час, превращается в часовой.

Разница между обновлением и заходом заново. Обновление страницы заставляет клиента проверять то, что он считал свежим; обычный переход — нет. Поэтому «у меня всё работает после обновления» ничего не доказывает.

Как проверять

Смотреть надо не на скорость, а на то, что происходит с запросами. В инструментах разработчика видно, какие ответы взяты из кеша, какие подтверждены проверкой, а какие пришли целиком. Три состояния, и путать их не стоит.

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

Проверять надо в трёх сценариях: первый заход, повторный переход по сайту и заход после выкатки новой версии. Третий важнее всех: именно там выясняется, что читатели видят старое.

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

Позиция редакции

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

Мы неправы, если содержимое по постоянному адресу заведомо не меняется — архивная публикация, снимок отчёта. Там длинный срок уместен и экономит заметно.

С чем это связано

Метка над заголовком говорит, зачем туда идти: продолжить тему, перейти к практике или увидеть возражение.

Сетка ячеек с заполненной частью изображает вес сборки, а рядом стоит отдельный счётчик другой величины — путь до первого действия: одно число больше не определпуть до действия
Углубление

Размер бандла больше не главная метрика

Глубже про измерения: почему байт не равен байту и что замерять вместо общего веса, чтобы видеть настоящую задержку.

На шкале времени жизни экрана величина — момент, когда становятся известны входные данные, — пробивает пороговую линию между сервером и клиентом: если данные изсервер/клиентвремя жизни экрана
Практика

Где проходит граница клиент — сервер

Куда именно провести границу в своём приложении: не по типам компонентов, а по моменту, когда становятся известны входные данные.

Прокси как граница: часть данных пересекает её и теряетсяснаруживнутри
Усиление

Обратный прокси: что он решает и что ломает

Тот же слой с другой стороны: настроенный однажды прокси остаётся источником неожиданных поломок, если его не проверять.

Письмо по вторникам

Один разбор недели и короткий список того, что изменилось. Без дайджестов на сорок ссылок.

Начните вводить — материалы появятся здесь.

выбрать · Enter открыть · Esc закрыть