Как настроить HTTP-кэширование API: ETag, Last-Modified, Vary

Всплески нагрузки и медленные ответы API бьют по конверсии и удержанию клиентов. Мы настраиваем HTTP-кэширование под ключ: разбираем причины отказов, проектируем режимы и внедряем так, чтобы повторные запросы отдавались мгновенно. В результате время ответа сокращается в разы, а инфраструктура перестаёт расти вместе с трафиком.

Разработка и обслуживание любых видов сайтов:

Информационные сайты или веб-приложения
Сайты визитки, landing page, корпоративные сайты, онлайн каталоги, квиз, промо-сайты, блоги, новостные ресурсы, информационные порталы, форумы, агрегаторы
Сайты или веб-приложения электронной коммерции
Интернет-магазины, B2B-порталы, маркетплейсы, онлайн-обменники, кэшбэк-сайты, биржи, дропшиппинг-платформы, парсеры товаров
Веб-приложения для управления бизнес-процессами
CRM-системы, ERP-системы, корпоративные порталы, системы управления производством, парсеры информации
Сайты или веб-приложения электронных услуг
Доски объявлений, онлайн-школы, онлайн-кинотеатры, конструкторы сайтов, порталы предоставления электронных услуг, видеохостинги, тематические порталы

Это лишь некоторые из технических типов сайтов, с которыми мы работаем, и каждый из них может иметь свои специфические особенности и функциональность, а также быть адаптированным под конкретные потребности и цели клиента

Услуги, которые мы предлагаем
Показано 1 из 1Все 2062 услуг
Как настроить HTTP-кэширование API: ETag, Last-Modified, Vary
Средний
от 1 дня до 3 дней
Часто задаваемые вопросы

HTTP-кэширование API: где ломается и что теряет заказчик

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

Дальше включается эффект домино. Нагрузка на бэкенд растёт вместе с числом клиентов, а не вместе с объёмом реально новых данных — типичная картина, когда 80% трафика приходится на одни и те же справочники, каталоги и списки. При пиковой нагрузке запас по ресурсам заканчивается раньше, чем приходит основной трафик, и начинаются отказы при пиках: сначала единичные таймауты, потом массовые ошибки на самых «горячих» эндпоинтах, которые как раз и вызываются чаще всего.

Кэширование API снимает эту нагрузку на уровне протокола, а не за счёт добавления серверов. Заголовки ETag и Last-Modified позволяют клиенту спросить «изменилось ли» и получить короткий ответ вместо полного тела, Vary разводит кэш по нужным признакам запроса, а корректные директивы свежести определяют, сколько ответ живёт без обращения к приложению. В результате повторные запросы закрываются на границе, а бэкенд занимается только новыми данными.

Разбираем, где именно ломается HTTP-кэширование в реальных API и как настроить его так, чтобы задержки и отказы перестали быть узким местом.

Что даёт управляемое кэширование: измеримые эффекты

HTTP-кэширование перестаёт быть «настройкой на глаз», когда у каждого ответа есть валидатор: ETag или Last-Modified. Клиент присылает If-None-Match / If-Modified-Since, сервер отвечает 304 Not Modified без тела — время ответа API на повторных запросах падает в разы, потому что по сети едет только заголовок, а не полезная нагрузка. Бэкенд при этом не пересобирает ответ: разгрузка идёт не за счёт кэша на стороне клиента, а за счёт того, что тяжёлая логика вообще не запускается.

Заголовок Vary решает вторую половину задачи — корректное разделение кэша по Accept-Encoding, Authorization и языку. Без него прокси отдаёт одному клиенту ответ, собранный для другого: чужие права, неверную локаль, сжатие не под тот формат. Это и есть отдельный класс отказов — не падение сервиса, а тихая выдача неверных данных, которую ловят уже в проде. Управляемое кэширование убирает его на уровне контракта, а не заплатками в коде.

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

Подходы к кэшированию: сравнение режимов и ограничений

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

Вариант Когда подходит Ограничения
Без кэширования Персональные данные, платёжные операции, ответы, зависящие от прав пользователя Каждый запрос идёт до источника, растёт нагрузка и задержка
Cache-Control: no-store Чувствительные ответы, которые нельзя оставлять на диске Не даёт выигрыша по скорости, только защищает данные
max-age + public Публичные справочники, каталоги, редко меняющийся контент Устаревание данных в пределах TTL, нужен сброс при обновлении
ETag + If-None-Match Ресурсы, которые меняются нечасто, но должны быть свежими Лишний round-trip на проверку, ответ 304 вместо тела
Last-Modified + If-Modified-Since Файлы, статика, документы с датой изменения Точность до секунды, ложные срабатывания при пересохранении
Vary по заголовкам Контент зависит от языка, авторизации, типа устройства Дробит кэш на много вариантов, растёт объём хранилища
Управляемые политики на прокси Единые правила для десятков сервисов Требуют согласования с приложением, иначе конфликт заголовков

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

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

Как мы внедряем кэширование: этапы инженерной работы

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

  1. Аудит заголовков. Снимаем реальные ответы API и смотрим, что отдаёт сервер сейчас: есть ли Cache-Control с осмысленным max-age, проставляется ли ETag или Last-Modified, не теряется ли Vary на заголовках авторизации и языка. Часто выясняется, что часть ответов кэшируется там, где не должна, а часть — наоборот, не кэшируется вовсе.
  2. Проектирование политик. Для каждого типа ресурса определяем режим: публичные справочники — долгий max-age с stale-while-revalidate, персональные данные — private без разделяемого кэша, изменяемые сущности — валидация через ETag и ответ 304. Отдельно фиксируем ключ кэша и набор полей в Vary.
  3. Настройка кэша. Прописываем заголовки на уровне приложения и промежуточного слоя, синхронизируем их между собой, чтобы прокси не переписывал политику приложения. Настраиваем корректную работу с условными запросами If-None-Match и If-Modified-Since.
  4. Проверка инвалидации. Прогоняем сценарии изменения данных: обновление записи, смена прав доступа, публикация новой версии. Убеждаемся, что после записи клиент и промежуточный кэш получают свежие данные, а не отдают устаревшие.
  5. Нагрузочная проверка. Смотрим долю ответов 304 и попаданий в кэш, время отклика до и после. Цель — рост доли валидированных ответов и снижение нагрузки на источник.
  6. Передача документации. Отдаём карту политик по эндпоинтам, правила инвалидации и инструкцию для разработчиков: какие заголовки менять можно, а какие сломают кэш.
  7. Сопровождение. После запуска отслеживаем метрики попаданий и корректируем max-age там, где данные меняются чаще, чем предполагалось.

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

Что заказчик получает на руки: конфигурации и регламенты

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

  • Конфигурации кэша — рабочие файлы для обратного прокси и приложения: правила по Cache-Control (max-age, s-maxage, stale-while-revalidate), генерация ETag и Last-Modified, настройка Vary под Accept-Encoding и авторизацию. С комментариями, почему выбран именно такой набор директив для каждого типа ответа.
  • Схемы потоков — диаграммы пути запроса: клиент → CDN → обратный прокси → приложение → хранилище. На схеме отмечено, на каком слое кэшируется ответ, где происходит ревалидация и какой слой отвечает за инвалидацию.
  • Политики инвалидации — регламент сброса: по тегам ресурсов, по префиксам URL, по событию изменения данных. С указанием, что чистится принудительно, а что живёт до истечения max-age, и как это соотносится с бизнес-логикой.
  • Документация API — описание эндпоинтов с указанием кэшируемости: какие ответы публичные, какие приватные, где обязательна авторизация и почему такой ответ не должен попадать в общий кэш.
  • Регламенты проверки — чек-лист приёмки: контроль заголовков ответа, поведение при 304 Not Modified, корректность Vary при разных Accept-Encoding, отсутствие утечки приватных данных через общий кэш.
  • Мониторинг и алерты — метрики доли попаданий в кэш, времени ответа на промахе и ревалидации. Пороги, при которых инженер получает уведомление, а не узнаёт о проблеме от пользователей.
  • Инструкция по откату — порядок действий, если новая политика кэширования ломает выдачу: как быстро сбросить кэш на всех слоях и вернуть предыдущую конфигурацию.

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

Кейс: как управляемое кэширование убрало всплески отказов

Проект — маркетплейс с каталогом на несколько сотен тысяч позиций и мобильным приложением, которое ходило в API за каждым экраном. Кэш-заголовков бэкенд не отдавал: Cache-Control не выставлялся, ETag не считался, ответы уходили с no-store по умолчанию. Каждый запуск приложения и каждый переход по каталогу били в базу напрямую.

Что было до внедрения

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

Что изменили

Настроили управляемое кэширование на уровне API-шлюза и приложения. Для справочников и карточек товаров включили ETag и Last-Modified — повторный запрос без изменений возвращает 304 Not Modified и не доходит до бэкенда. Для списков, зависящих от фильтров, ролей и языка, прописали Vary по нужным заголовкам, чтобы не отдавать чужую версию ответа. Публичные данные получили Cache-Control с раздельными директивами max-age и stale-while-revalidate: клиент отдаёт устаревшую копию, пока фоном подтягивается свежая. Инвалидацию привязали к событиям изменения товара, а не к таймеру.

Что стало

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

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

Чем отличается ETag от Last-Modified и когда нужен Vary?

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

На практике их не противопоставляют, а ставят вместе: ETag даёт точную проверку, Last-Modified остаётся запасным валидатором для посредников, которые не умеют работать с отпечатком. Клиент шлёт условный запрос с If-None-Match и If-Modified-Since, сервер сравнивает и возвращает либо тело, либо короткий ответ «не изменилось» — экономия трафика и времени ответа на порядок, а не на проценты.

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

Vary отвечает на другой вопрос — не «та же ли это версия», а «тот же ли это клиент». Если ответ зависит от заголовка Accept, Accept-Encoding, Accept-Language или авторизации, без Vary промежуточный кэш отдаст чужую версию: сжатый ответ — клиенту без поддержки сжатия, английский — тому, кто просил русский. Vary: Accept-Encoding и Vary: Accept-Language закрывают это, но каждый добавленный заголовок дробит кэш на большее число вариантов, поэтому перечислять нужно только то, что реально влияет на тело ответа.

Отдельно стоит Vary: Authorization и приватные ответы: их либо помечают Cache-Control: private, либо запрещают кэширование вовсе, иначе персональные данные осядут в общем кэше. Проверять связку удобно по журналу: доля ответов «не изменилось» на условные запросы показывает, работает ли валидация, а доля попаданий в кэш по каждому варианту Vary — не разрастается ли хранилище.

Частые технические сомнения при настройке кэширования

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

Авторизация и кэш конфликтуют там, где ответ зависит от пользователя, а ключ кэша — только от URL. Решение — либо явный Cache-Control: private для таких маршрутов, либо Vary: Authorization, либо разделение на публичный и приватный контуры. Мы не полагаемся на «по умолчанию не закэшируется»: проверяем каждый маршрут, где в ответе есть данные пользователя.

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

У нас уже развёрнут кэш — придётся всё перестраивать?

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

Как не сломать авторизацию при включении кэша?

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

Как убедиться, что инвалидация работает?

Проверяем цепочку: обновили ресурс — изменился ли ETag или Last-Modified, вернул ли сервер 304 на условный запрос, ушёл ли старый ответ с прокси. Если хотя бы один шаг не срабатывает, кэш отдаёт устаревшее.

Эти сомнения всплывают почти на каждом проекте — и почти всегда решаются точечной настройкой, а не переписыванием. Опишите вашу конфигурацию — вернёмся с оценкой и планом проверки.

Обсудим вашу задачу по кэшированию API

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

Что полезно приложить к описанию:

  • текущие заголовки ответов API — Cache-Control, ETag, Last-Modified, Vary: видно, что уже отдаётся клиентам и где логика рассыпается;
  • архитектуру: монолит или несколько сервисов, есть ли CDN или обратный прокси перед приложением;
  • какие методы и эндпоинты кэшируются, а какие должны оставаться строго свежими (платежи, балансы, статусы заказов);
  • как устроена авторизация — токены в заголовке, cookie, сессии: от этого зависит корректная настройка Vary и приватности кэша;
  • жалобы от пользователей или метрики: устаревшие данные, лишние запросы, рост нагрузки на базу;
  • ограничения: регламенты, требования к безопасности, сроки, которые нельзя сдвигать.

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

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

Наши компетенции:

Последние работы

  • Разработка сайта компании B2B ADVANCE
    Разработка сайта компании B2B ADVANCE
    1542
  • Разработка веб-приложения для компании FEEDME
    Разработка веб-приложения для компании FEEDME
    1394
  • Разработка веб-сайта для компании БЕЛФИНГРУПП
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    1081
  • Разработка интернет магазина для компании FURNORO
    Разработка интернет магазина для компании FURNORO
    1369
  • Разработка веб-приложения для компании Enviok
    Разработка веб-приложения для компании Enviok
    1142
  • Разработка веб-сайта для компании ФИКСПЕР
    Разработка веб-сайта для компании ФИКСПЕР
    1060