Клиент часто запрашивает ресурс, который меняется редко. Как API проверит его актуальность без передачи полного тела при каждом запросе?
API должен использовать условные запросы с валидатором представления ресурса, обычно ETag. Клиент сохраняет полученный ETag и передаёт его при следующем запросе; если ресурс не изменился, сервер отвечает 304 Not Modified без повторной передачи тела.
Проверка актуальности появилась как способ снизить сетевой трафик и задержку при работе с повторно запрашиваемыми ресурсами. Простого кэширования по времени недостаточно: ресурс может измениться раньше истечения срока хранения или остаться неизменным после него.
Валидаторы позволили отделить проверку версии ресурса от повторной передачи его содержимого. Это особенно важно для крупных ответов, медленных каналов и систем с большим числом клиентов.
Если клиент каждый раз получает полное представление ресурса, растут нагрузка на сеть, сервер и время ответа. Если клиент без проверки использует локальную копию, он может показать устаревшие данные.
Неверный валидатор также создаёт риск: если он не меняется при изменении содержимого, сервер ошибочно вернёт 304 Not Modified. Если валидатор нестабилен и меняется без изменения представления, клиент будет получать полное тело без необходимости.
Сервер формирует ETag для конкретного представления ресурса и возвращает его вместе с телом. Клиент сохраняет это значение, а в следующем запросе передаёт его в условном заголовке. Сервер сравнивает полученный ETag с текущим.
Если версии совпадают, сервер возвращает 304 Not Modified; тело ответа отсутствует, а клиент использует свою корректную копию. Если версии различаются, сервер возвращает обычный успешный ответ с новым телом и новым ETag.
ETag должен однозначно отражать версию выбранного представления, а не обязательно всей внутренней записи. Например, разные варианты представления одного ресурса могут иметь разные валидаторы. Слабый валидатор, обозначаемый префиксом W/, допускает семантически эквивалентные, но побайтно разные представления и подходит не для всех операций сравнения.
Условная проверка актуальности не заменяет управление сроком хранения. Заголовки кэширования определяют, когда клиент может использовать копию без обращения к серверу, а ETag позволяет проверить эту копию после обращения.
Для изменения ресурса ETag также может применяться как условие записи: клиент сообщает версию, на основе которой редактировал данные, а сервер отклоняет запись при несовпадении. Это защищает от перезаписи чужих изменений, но является отдельным сценарием по сравнению с условным чтением.
Мобильное приложение часто открывает карточку тарифа размером 800 КБ. Рассматривались три варианта: всегда передавать полное тело, использовать фиксированный короткий срок кэширования или применять ETag.
Полная передача проста, но создаёт лишний трафик. Фиксированный срок снижает нагрузку, однако данные могут быть устаревшими до его окончания; слишком короткий срок уменьшает этот риск ценой дополнительных запросов. ETag требует хранения валидатора и сравнения на сервере, зато позволяет часто подтверждать актуальность почти без передачи тела.
Выбран ETag совместно с разумными правилами кэширования. При неизменном тарифе клиент получал 304 Not Modified, а после публикации новой версии — полное тело и новый ETag. Это сократило объём передаваемых данных, сохранив явную проверку актуальности.
1. Достаточно ли ETag, чтобы клиент всегда видел самые свежие данные?
Нет. ETag работает только в момент обращения к серверу. Если клиенту разрешено использовать кэш без проверки в течение заданного срока, он может видеть устаревшее значение до окончания этого срока. Поэтому отдельно проектируют политику кэширования и требования к допустимой свежести данных.
2. Можно ли строить ETag только по времени изменения записи?
Можно, но это требует осторожности. Временная метка должна надёжно меняться при каждом значимом изменении выбранного представления и иметь достаточную точность. Если изменения происходят в пределах одной различимости времени или представление зависит от других данных, одинаковая метка может скрыть обновление; хеш содержимого или надёжная версия обычно безопаснее.
3. Чем условное чтение отличается от защиты записи через тот же ETag?
При чтении клиент сообщает, какая версия у него уже есть, чтобы сервер решил, нужно ли передавать тело. При записи клиент сообщает версию, на которой основаны его изменения, чтобы сервер обнаружил конфликт. В первом случае результатом совпадения обычно становится 304 Not Modified, во втором несовпадение должно привести к отказу или конфликту, а не к молчаливому затиранию обновления.