HTTPQUERY
Русский

304 Not Modified

Применение

Код состояния 304 Not Modified отправляется, когда запрос безопасный — например GET или HEAD — и сервер определяет, что ресурс не изменился по сравнению с версией, сохранённой в кэше клиента. Это экономит трафик, поскольку сервер не передаёт повторно данные, которые у клиента уже есть.

Примечание

304 Not Modified не является перенаправлением, несмотря на принадлежность к классу состояний 3xx. Перенаправления (301, 302, 307, 308) направляют клиента на другой URL через заголовок Location. А 304 сообщает клиенту, что нужно повторно использовать закэшированную копию того же ресурса, и заголовок Location не отправляется. Инструменты разработчика в браузере иногда группируют 304 вместе с перенаправлениями, что усиливает путаницу.

Примечание

Запись “200 (from disk cache)” в инструментах разработчика означает, что браузер отдал ресурс из кэша, не обращаясь к серверу, поскольку срок max-age из Cache-Control ещё не истёк. А 304 означает, что браузер обратился к серверу для повторной валидации и сервер подтвердил актуальность закэшированной копии. Закэшированный 200 не требует ни одного сетевого запроса, тогда как 304 требует одного обмена с сервером.

Сервер формирует в ответе один или несколько следующих заголовков:

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

Для условных запросов GET значимыми директивами являются If-None-Match и If-Modified-Since. Они опираются на валидатор, такой как ETag, чтобы определить, нужна ли повторная передача ресурса.

Пример

Клиент запрашивает ресурс, получает ETag, идентифицирующий версию, а затем выполняет повторную валидацию. Сервер определяет, что ресурс не изменился, и возвращает 304 Not Modified. При третьем запросе доступна новая версия, поэтому отправляется полный ответ 200 с обновлённым ETag.

Примечание

Каждый раз, когда сервер обновляет ресурс, генерируется новый ETag. Как вариант, сервер возвращает дату Last-Modified, а клиент использует вместо этого If-Modified-Since, что избавляет сервер от необходимости хранить историю ETag.

Влияние на SEO

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

Ловушка устаревшего 304

Ответ 304 подтверждает, что закэшированная версия по-прежнему актуальна. Если сервер ранее отдал сломанную страницу (пустое тело, содержимое с ошибкой) с кодом 200 и робот закэшировал этот результат, то последующий 304 сообщит роботу, что сломанная версия сохраняется. Робот перестаёт перепроверять страницу, потому что «содержимое» не изменилось. Одного лишь исправления страницы недостаточно. Сервер должен вернуть свежий ответ 200 с исправленным телом (и новым ETag), чтобы заменить закэшированную ошибку. Отлаживать такой сценарий трудно, потому что первопричина (прошлая кратковременная ошибка) больше не видна.

Первоначальный запрос

GET /news.html HTTP/1.1
Host: example.com

Первоначальный ответ

HTTP/1.1 200 OK
ETag: "1234000"
Content-Type: text/html
Content-Length: 1250

<message body contains requested resource>

Второй запрос

GET /news.html HTTP/1.1
Host: example.com
If-None-Match: "1234000"

Второй ответ

HTTP/1.1 304 Not Modified
ETag: "1234000"

Третий запрос

GET /news.html HTTP/1.1
Host: example.com
If-None-Match: "1234000"

Третий ответ

HTTP/1.1 200 OK
ETag: "1234001"
Content-Type: text/html
Content-Length: 1600

<message body contains requested resource>

Примеры кода

.NET

HttpStatusCode.NotModified

Rust

http::StatusCode::NOT_MODIFIED

Rails

:not_modified

Go

http.StatusNotModified

Symfony

Response::HTTP_NOT_MODIFIED

Python3.5+

http.HTTPStatus.NOT_MODIFIED

Java

java.net.HttpURLConnection.HTTP_NOT_MODIFIED

Apache HttpComponents Core

org.apache.hc.core5.http.HttpStatus.SC_NOT_MODIFIED

Angular

@angular/common/http/HttpStatusCode.NotModified