Открыть сервис

HTTP-заголовок ETag

ETag (Entity Tag, тег сущности) — это один из механизмов протокола HTTP, предназначенный для управления кэшированием и проверки целостности содержимого ресурса. Представляет собой строку-идентификатор, которая присваивается сервером конкретной версии ресурса (например, HTML-страницы, изображения, JSON-ответа). При изменении содержимого ресурса сервер генерирует новое значение ETag, что позволяет клиенту (браузеру, прокси-серверу) и серверу эффективно определять, изменился ли ресурс с момента последнего запроса, без необходимости повторной передачи всего содержимого.

Принцип работы

ETag функционирует в рамках механизма условных запросов HTTP. Клиент, получив от сервера ответ с заголовком ETag, сохраняет это значение. При повторном запросе того же ресурса клиент отправляет серверу заголовок If-None-Match, содержащий сохранённое значение ETag. Сервер сравнивает полученное значение с текущим ETag запрашиваемого ресурса:

  • Если значения совпадают, ресурс не изменился. Сервер возвращает ответ со статусом 304 Not Modified (не изменялся) и пустым телом. Клиент использует свою локальную копию.
  • Если значения не совпадают, ресурс был изменён. Сервер возвращает полный ответ со статусом 200 OK и новым содержимым, а также новым значением ETag.

Аналогичный механизм используется для заголовка If-Match, который, наоборот, требует совпадения ETag для выполнения запроса. Это применяется для предотвращения конфликтов при одновременном редактировании ресурса (например, при использовании HTTP-метода PUT).

Формат и типы

Значение ETag представляет собой строку, заключённую в двойные кавычки. Сервер может генерировать его произвольным образом, но обычно это хеш-сумма содержимого (например, MD5, SHA-1) или метка времени, связанная с версией файла.

Различают два основных типа ETag:

Сильный ETag (Strong ETag)

Сильный ETag изменяется при любом, даже самом незначительном изменении содержимого ресурса. Гарантирует, что два ресурса с одинаковым сильным ETag являются полностью идентичными байт-в-байт. Формат: "<значение>". Например: "33a64df551425fcc55e4d42a148795d9f25f89d4".

Слабый ETag (Weak ETag)

Слабый ETag допускает, что ресурсы могут считаться эквивалентными для целей кэширования, даже если их содержимое не идентично на уровне байтов (например, из-за незначительных изменений форматирования или динамических элементов). Обозначается префиксом W/ перед значением. Формат: W/"<значение>". Например: W/"0815". Слабые ETag не подходят для проверки целостности при использовании If-Match.

Применение

Кэширование

Основное назначение ETag — оптимизация загрузки веб-страниц. В сочетании с другими заголовками кэширования (например, Cache-Control, Expires) ETag позволяет клиентам и промежуточным кэшам (прокси-серверам) избегать повторной загрузки неизменённых ресурсов. Это снижает нагрузку на сервер и уменьшает объём передаваемых данных, что особенно важно для мобильных устройств и медленных соединений.

Управление параллелизмом (Concurrency Control)

В RESTful API заголовок If-Match с ETag используется для реализации оптимистичной блокировки. Клиент, получив ресурс, запоминает его ETag. При отправке запроса на обновление (PUT) клиент включает в запрос заголовок If-Match с этим ETag. Сервер проверяет, совпадает ли текущий ETag ресурса с переданным. Если нет (ресурс был изменён другим клиентом), сервер возвращает ошибку 412 Precondition Failed (Предусловие не выполнено), предотвращая перезапись изменений.

Проверка целостности

ETag может использоваться для проверки того, что загруженный клиентом фрагмент большого файла (при использовании запросов с диапазонами, Range) не был повреждён. Сервер может возвращать ETag для каждого диапазона, а клиент — проверять его при сборке файла.

Ограничения и особенности

  • Вычислительная нагрузка: Генерация ETag, особенно сильного, требует вычисления хеш-суммы содержимого, что может создавать дополнительную нагрузку на сервер для динамически генерируемых страниц. Для статических файлов (изображения, CSS, JavaScript) ETag часто вычисляется на основе метаданных файловой системы (inode, размер, время изменения), что очень эффективно.
  • Проблемы с балансировкой нагрузки: В кластерных конфигурациях, где несколько серверов обслуживают один сайт, ETag, основанный на внутренних идентификаторах файловой системы (например, inode в Unix), может различаться на разных серверах для одного и того же файла. Это приводит к ложным срабатываниям механизма кэширования. Решением является использование ETag, основанного только на содержимом (хеш-сумма) или настройка единого хранилища.
  • Не является заменой Cache-Control: ETag не определяет политику кэширования (как долго кэшировать, можно ли хранить в общем кэше). Он лишь предоставляет механизм проверки актуальности. Политика кэширования задаётся заголовком Cache-Control.
  • Безопасность: ETag не предназначен для аутентификации или авторизации. Он не является секретом и не должен использоваться для контроля доступа. Однако в некоторых случаях ETag может использоваться для отслеживания пользователей (например, для подсчёта уникальных посетителей), что является потенциальной проблемой приватности.

Взаимодействие с другими заголовками

ETag работает в тесной связке с другими заголовками HTTP:

  • If-None-Match: Используется клиентом для условного GET-запроса.
  • If-Match: Используется клиентом для условного PUT или DELETE-запроса.
  • If-Modified-Since: Альтернативный механизм проверки актуальности, основанный на дате последнего изменения ресурса. Сервер может поддерживать оба механизма. ETag считается более точным, так как дата может не отражать реальных изменений (например, при изменении метаданных).
  • Cache-Control: Определяет, может ли ответ кэшироваться и на какой срок. ETag используется для проверки актуальности кэшированной копии по истечении этого срока.

Примеры использования

Пример 1: Условный GET-запрос

Запрос клиента (первый): `` GET /image.jpg HTTP/1.1 Host: example.com ``

Ответ сервера: ``` HTTP/1.1 200 OK Content-Type: image/jpeg ETag: "abc123" Content-Length: 1024

[данные изображения] ```

Запрос клиента (повторный): `` GET /image.jpg HTTP/1.1 Host: example.com If-None-Match: "abc123" ``

Ответ сервера (если изображение не изменилось): `` HTTP/1.1 304 Not Modified ETag: "abc123" ``

Пример 2: Оптимистичная блокировка (REST API)

Запрос на получение ресурса: `` GET /api/users/123 HTTP/1.1 Host: api.example.com ``

Ответ сервера: ``` HTTP/1.1 200 OK Content-Type: application/json ETag: "user-123-v1"

{"id": 123, "name": "Иван"} ```

Запрос на обновление (с проверкой): ``` PUT /api/users/123 HTTP/1.1 Host: api.example.com Content-Type: application/json If-Match: "user-123-v1"

{"id": 123, "name": "Пётр"} ```

Ответ сервера (если ресурс не был изменён другим клиентом): `` HTTP/1.1 200 OK ETag: "user-123-v2" ``

Ответ сервера (если ресурс был изменён): `` HTTP/1.1 412 Precondition Failed ``

История

Механизм ETag был впервые определён в спецификации HTTP/1.1 (RFC 2616, 1999 год). Впоследствии он был уточнён в RFC 7232 (2014 год), который заменил соответствующую часть RFC 2616. В RFC 7232 были более чётко разграничены понятия сильного и слабого ETag, а также уточнены правила их сравнения и использования в условных запросах.

Источники

  • RFC 7232 — Hypertext Transfer Protocol (HTTP/1.1): Conditional Requests
  • RFC 2616 — Hypertext Transfer Protocol — HTTP/1.1 (раздел 13.3.2, устаревший)
  • Документация по HTTP-заголовкам на MDN Web Docs (Mozilla Developer Network)

BFOmetr — база данных и аналитика по компаниям России.

На главную BFOmetr →