304 Not Modified: почему это успех, а не ошибка
304 Not Modified - это успех: он означает, что ваша закэшированная копия ресурса по-прежнему актуальна, поэтому сервер не отправляет тело ответа и велит переиспользовать уже имеющееся у вас. Он появляется только в ответ на условный запрос, поэтому проверка мониторинга, не отправляющая заголовков кэша, никогда его не увидит.
Как возникает 304
304 - это вторая половина двухшагового диалога. На первый запрос сервер возвращает ресурс вместе с валидатором:
ETag, непрозрачным идентификатором именно этой версии, и часто датой Last-Modified. Клиент
сохраняет ответ вместе с этими валидаторами.
Позже, когда закэшированную копию нужно перепроверить, клиент повторяет запрос и добавляет то, что у него есть:
If-None-Match: "abc123"несет сохраненный ETag. Это предпочтительный валидатор, поскольку он точный.If-Modified-Since: Wed, 03 Sep 2026 10:00:00 GMTнесет сохраненную дату, используется при отсутствии ETag.
Если ресурс не изменился, сервер отвечает 304 Not Modified только с заголовками и без тела, и клиент
отображает свою закэшированную копию. Если ресурс изменился, сервер отвечает 200 с новым содержимым и новыми валидаторами.
Оба исхода - правильное поведение.
Почему 304 - хорошая новость, а не ошибка
Люди видят 304 в панели сети браузера или анализаторе логов, замечают, что это не 200, и решают, что что-то сломалось. Ничего не сломалось. 304 - самый дешевый полезный ответ в вебе: тело ответа вообще не передается по сети, так что передача занимает несколько сотен байт вместо полного ресурса, а сервер обычно избегает пересоздания ресурса, так что это стоит меньше процессорного времени, чем 200. Страница отрисовывается быстрее, потому что браузер переиспользует уже имеющиеся байты. Краулерам это тоже выгодно: стабильный ETag, дающий 304, позволяет поисковой системе тратить бюджет обхода на страницы, которые действительно изменились.
Высокая доля 304 на статических ресурсах - признак того, что кэширование настроено хорошо. Единственное, за чем
стоит следить, - нужен ли вообще этот раунд перепроверки: для версионированных или помеченных отпечатком ресурсов
длинный Cache-Control: max-age с immutable позволяет избежать даже 304, потому что браузер
вовсе не спрашивает.
Когда 304 - это проблема
- Устаревшая страница, которая не обновляется. Если ваш HTML отдается с валидатором, который никогда не меняется, пока меняется содержимое, браузеры продолжают получать 304, а пользователи - видеть старую страницу. Это классический баг "я задеплоил, но никто не видит изменений".
- 304 без соответствующей закэшированной копии. Если клиент отправляет условный запрос, на который у него не было оснований, или прокси вырезает тело из ответа 200, клиенту нечего отрисовывать, и страница оказывается пустой.
- Слабые или нестабильные ETag за балансировщиком нагрузки. Когда несколько бэкендов генерируют разные ETag для идентичного содержимого, каждая перепроверка промахивается, и вместо ожидаемых 304 вы получаете полные 200. Трафик растет без причины.
- Сжатие меняет валидатор. Если ETag различается между сжатым и несжатым вариантами без корректного
Vary: Accept-Encoding, кэши могут отдать не то.
Как проверить условные запросы
- Получите ресурс и прочитайте его валидаторы:
curl -sI https://example.com/style.css | grep -Ei "^(HTTP|etag|last-modified|cache-control)" - Повторите запрос с полученным ETag и убедитесь, что сервер отвечает 304:
Подставьте точное значение ETag, включая кавычки. Ответ 200 здесь означает, что перепроверка не работает.curl -sI -H 'If-None-Match: "abc123"' https://example.com/style.css | head -n 1 - Если вместо ожидаемого 304 приходит 200, проверьте, не вырезает ли прокси или CDN заголовок
If-None-Match, и совпадает ли ETag для одного и того же файла у всех ваших бэкендов. - Если страница отдается устаревшей, сделайте так, чтобы валидатор менялся при изменении содержимого. Имена файлов с отпечатком содержимого - самое надежное решение; в остальных случаях выводите ETag из самого содержимого.
- Держите HTML с коротким сроком свежести, а ресурсам оставляйте длинный. Именно кэширование HTML на сутки делает деплой невидимым для пользователей.
Почему проверки аптайма никогда не видят 304
Проверка аптайма запрашивает страницу как первый посетитель, без If-None-Match и без If-Modified-Since,
поэтому серверу не с чем сравнивать, и он всегда отвечает 200. Это правильное поведение по умолчанию для проверки
доступности. Это также означает, что регрессии кэширования вообще не проявляются в данных аптайма: сайт может отдавать
всем устаревшую страницу, пока каждая проверка остается зеленой. Проверяйте содержимое страницы наравне со статусом,
и страница, переставшая обновляться, станет видна как несовпадение содержимого. HostTracker предлагает 13 типов
мониторов и следит за сайтами с 2004 года. Проверьте заголовки и статус с помощью инструмента HTTP-проверки, а о том, что на самом деле доказывает 200 OK, читайте отдельно, как и в полном руководстве по семейству 3xx.