Что означает статус ответа 304 в HTTP
Что проверяют
Понимаете ли вы условные запросы и валидацию кэша, а не только то, что ответ пришёл из кэша. От бэкендера на Go дополнительно ждут знания, что у такого ответа не бывает тела и что стандартная библиотека умеет это сама.
Как отвечать
Статус 304 Not Modified приходит на условный запрос. Клиент уже держит копию ресурса и спрашивает, изменилась ли она: шлёт If-None-Match с ранее полученным ETag либо If-Modified-Since с датой из Last-Modified. Если версия совпала, сервер отвечает 304 без тела, а клиент берёт свою копию и продлевает срок её годности.
Что стоит сказать помимо определения:
- у 304 нет тела: после
w.WriteHeader(http.StatusNotModified)писать в ответ нельзя; - вместе с 304 отправляются заголовки валидации и кэширования, иначе следующий цикл проверки сломается;
ETagнадёжнее даты:Last-Modifiedимеет секундную точность и не различает две правки внутри одной секунды;- в стандартной библиотеке
http.ServeContentиhttp.ServeFileразбирают условные заголовки и отдают 304 сами; - 304 экономит трафик и сериализацию, но не сетевой круг. Чтобы убрать сам запрос, нужен
Cache-Controlс временем жизни.
Где спотыкаются
Трактуют 304 как ошибку. В клиентском коде появляется проверка статуса на равенство двумстам, и валидный ответ уходит в ветку сбоя. Стандартный клиент Go возвращает 304 как обычный ответ, обрабатывать его надо отдельной веткой.
Пишут тело вместе со статусом. Сервер такой ответ обрезает и ругается в лог, а прокси и браузеры ведут себя по-разному, вплоть до подвисших запросов.
Генерируют ETag нестабильно: от времени генерации ответа, от адреса объекта в памяти или от обхода карты, порядок которой в Go случаен. Значение меняется на каждом ответе или различается между инстансами, и 304 не наступает никогда. Считать его надо от детерминированного представления данных.