Перейти к основному содержимому

Руководства / Коды состояния HTTP: разбор

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, кэши могут отдать не то.

Как проверить условные запросы

  1. Получите ресурс и прочитайте его валидаторы:
    curl -sI https://example.com/style.css | grep -Ei "^(HTTP|etag|last-modified|cache-control)"
  2. Повторите запрос с полученным ETag и убедитесь, что сервер отвечает 304:
    curl -sI -H 'If-None-Match: "abc123"' https://example.com/style.css | head -n 1
    Подставьте точное значение ETag, включая кавычки. Ответ 200 здесь означает, что перепроверка не работает.
  3. Если вместо ожидаемого 304 приходит 200, проверьте, не вырезает ли прокси или CDN заголовок If-None-Match, и совпадает ли ETag для одного и того же файла у всех ваших бэкендов.
  4. Если страница отдается устаревшей, сделайте так, чтобы валидатор менялся при изменении содержимого. Имена файлов с отпечатком содержимого - самое надежное решение; в остальных случаях выводите ETag из самого содержимого.
  5. Держите HTML с коротким сроком свежести, а ресурсам оставляйте длинный. Именно кэширование HTML на сутки делает деплой невидимым для пользователей.

Почему проверки аптайма никогда не видят 304

Проверка аптайма запрашивает страницу как первый посетитель, без If-None-Match и без If-Modified-Since, поэтому серверу не с чем сравнивать, и он всегда отвечает 200. Это правильное поведение по умолчанию для проверки доступности. Это также означает, что регрессии кэширования вообще не проявляются в данных аптайма: сайт может отдавать всем устаревшую страницу, пока каждая проверка остается зеленой. Проверяйте содержимое страницы наравне со статусом, и страница, переставшая обновляться, станет видна как несовпадение содержимого. HostTracker предлагает 13 типов мониторов и следит за сайтами с 2004 года. Проверьте заголовки и статус с помощью инструмента HTTP-проверки, а о том, что на самом деле доказывает 200 OK, читайте отдельно, как и в полном руководстве по семейству 3xx.

Проверить сейчас

Запустите бесплатную проверку своего сайта - аккаунт не нужен.

HTTP check

Следить за этим постоянно

Получайте оповещение в момент сбоя: HostTracker проверяет более чем из 300 локаций и уведомляет по email, SMS, в Slack, Telegram и не только.

Возможности HostTracker

Ещё в этом разделе: Коды состояния HTTP: разбор