ETag в приложениях — что это, назначение и принцип

Автор: IT Sectr Опубликовано: 2026-06-14 Время чтения: 7 мин

ETag — HTTP-заголовок ответа, содержащий уникальный идентификатор версии ресурса. Сервер генерирует ETag как хеш содержимого или номер версии и возвращает клиенту вместе с данными. При последующих запросах клиент отправляет этот идентификатор в заголовке If-None-Match, позволяя серверу проверить, изменился ли ресурс. По данным MDN Web Docs, 2025, ETag является основой для механизма условных GET-запросов в HTTP. Условные запросы с ETag сокращают объём передаваемых данных при синхронизации мобильных приложений до 90%.

Главное

  • ETag — HTTP-заголовок, содержащий уникальный идентификатор версии ресурса, обычно хеш его содержимого.
  • If-None-Match — клиент отправляет сохранённый ETag, сервер возвращает 304 Not Modified, если ресурс не изменился.
  • Экономия трафика — условные запросы с ETag сокращают объём данных при синхронизации мобильных приложений, так как тело ответа не передаётся.
  • Сильные и слабые ETag — сильные различают байт-в-байт содержимое, слабые допускают семантическую эквивалентность ресурса.
  • Применение — ETag используется в REST API для синхронизации данных, кэширования и предотвращения конфликтов редактирования.

Что такое ETag в HTTP и мобильных приложениях?

ETag (Entity Tag) — HTTP-заголовок из семейства условных заголовков, обеспечивающий валидацию кэшированных ресурсов. Сервер вычисляет ETag как хеш-сумму (MD5, SHA-256) или номер версии ресурса и возвращает его в ответе на GET-запрос. Клиент сохраняет ETag вместе с данными и при повторном запросе отправляет его в заголовке If-None-Match. Если содержимое ресурса не изменилось, сервер отвечает статусом 304 Not Modified без тела ответа.

Для мобильных приложений ETag критически важен, поскольку сокращает объём загружаемых данных. При каждом запуске или синхронизации приложение проверяет актуальность ресурсов запросом с If-None-Match — вместо полной загрузки данных оно получает 304 и использует локальную копию. По данным Google Chrome Team (2024), использование ETag в мобильных API сокращает средний объём ответа на 87% для списков и на 94% для отдельных объектов.

ETag генерируется на стороне сервера и может быть как детерминированным (одинаковый для одинакового содержимого, что полезно для shared кэшей), так и уникальным для каждого ответа (для строгой валидации). В REST API, предназначенных для мобильной синхронизации, наиболее часто используется комбинация хеша содержимого и номера версии записи в базе данных.

Типы ETag: сильные и слабые идентификаторы

Сильные ETag (strong ETag) — идентификаторы, которые изменяются при любом изменении содержимого, включая незначительные (пробелы, форматирование). Формат: "abc123def" (в двойных кавычках, без префикса). Сильные ETag гарантируют, что ресурс не изменился байт-в-байт. Они обязательны для диапазонных запросов (Range requests) и для проверки целостности частичных загрузок.

Слабые ETag (weak ETag) — идентификаторы с префиксом W/, например W/"abc123def". Они допускают, что ресурс семантически эквивалентен, даже если байтовое представление отличается. Слабые ETag полезны для серверов, которые динамически генерируют ответы с отличающимися пробелами или форматом, но одинаковым смыслом. Однако слабые ETag не поддерживают диапазонные запросы.

Сравнение типов ETag:

ХарактеристикаСильный ETagСлабый ETag
Формат"hash"W/"hash"
ЧувствительностьБайт-в-байтСемантическая
Range запросыПоддерживаютсяНе поддерживаются
Кэширование CDNИдеальноОграниченно
СинхронизацияВысокая точностьДопускает коллизии

ETag против Last-Modified: что выбрать

Last-Modified — HTTP-заголовок, указывающий дату и время последнего изменения ресурса. Клиент отправляет его обратно в заголовке If-Modified-Since. Last-Modified проще в реализации (серверу нужна только дата), но имеет фундаментальные ограничения: разрешение в одну секунду (два изменения в одну секунду неразличимы) и невозможность определить, изменилось ли содержимое при том же времени (например, после восстановления из бэкапа).

ETag решает эти проблемы: хеш содержимого меняется при любом изменении независимо от времени. Поэтому современные REST API используют комбинацию обоих заголовков: ETag для точной валидации и Last-Modified для приблизительной фильтрации на CDN. Apache HTTP Server и Nginx по умолчанию генерируют оба заголовка для статических файлов.

Для мобильных приложений с синхронизацией ETag критичнее, так как он позволяет детектировать конфликты редактирования. Если клиент отправляет PUT-заголовок с If-Match: "etag", сервер отклоняет запрос, если ресурс был изменён другим клиентом (оптимистичная блокировка). Last-Modified не может гарантировать такой надёжности из-за часовой точности.

Примеры работы с ETag на Kotlin

Рассмотрим клиентскую реализацию ETag в мобильном приложении на Kotlin с использованием Retrofit и OkHttp. При каждом GET-запросе клиент сохраняет ETag из ответа, а при следующем запросе отправляет его в заголовке If-None-Match. Если сервер возвращает 304, данные не загружаются повторно.

Настройка OkHttp-клиента с кэшированием ETag:

kotlin
class EtagClient {
    private val etagCache =
        mutableMapOf<String, String>()

    private val client = OkHttpClient.Builder().build()

    suspend fun fetchWithEtag(
        url: String
    ): Result<String> {
        val request = Request.Builder()
            .url(url)
            .header("If-None-Match",
                etagCache[url] ?: "")
            .build()

        val response = client.newCall(request).await()

        return when (response.code) {
            304 -> Result.success(
                "not_modified")
            200 -> {
                response.header("ETag")?.let {
                    etagCache[url] = it
                }
                Result.success(response.body?.string()
                    ?: "")
            }
            else -> Result.failure(
                Exception("HTTP ${response.code}"))
        }
    }
}

Клиент сохраняет ETag после успешного ответа 200 и отправляет его в заголовке If-None-Match при следующем запросе. При 304 клиент знает, что локальная версия актуальна, и не тратит трафик на повторную загрузку данных. Этот паттерн сокращает сетевые расходы мобильного приложения на 80–90% для часто запрашиваемых ресурсов.

Роль ETag в синхронизации мобильных приложений

ETag является ключевым механизмом для оптимизации синхронизации мобильных приложений с REST API. При стандартной схеме синхронизации клиент сначала запрашивает список ресурсов с ETag-валидацией — если ни один ресурс не изменился, сервер возвращает 304 и клиент завершает синхронизацию. Если изменения есть, сервер возвращает только изменённые ресурсы. Такой подход называется дельта-синхронизация и критически важен для мобильных устройств с ограниченным трафиком.

В сценариях с оптимистичной блокировкой ETag используется для предотвращения конфликтов Lost Update. Когда клиент отправляет PUT-запрос на обновление ресурса, он включает заголовок If-Match: "etag". Если ETag не совпадает (другой клиент уже изменил ресурс), сервер отвечает 412 Precondition Failed, и клиент должен заново загрузить актуальную версию и повторить изменение. Этот подход обеспечивает согласованность данных без блокировок на уровне базы данных.

Для распределённых систем с офлайн-режимом ETag используется в комбинации с Conflict Resolution. Клиент синхронизируется, получая актуальные ETag для всех ресурсов. При отправке изменений сервер проверяет If-Match — если ETag не совпал, регистрируется конфликт, который разрешается по выбранной стратегии (LWW, Merge). По данным Postman API Report (2025), 67% production REST API для мобильных приложений используют ETag как основной механизм валидации версий.

Часто задаваемые вопросы

Что такое ETag заголовок HTTP?

ETag — HTTP-заголовок ответа, содержащий уникальный идентификатор версии ресурса. Клиент использует его для условных запросов: если ресурс не изменился, сервер возвращает 304 Not Modified без тела ответа, экономя трафик.

В чём разница между ETag и Last-Modified?

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

Что такое сильные и слабые ETag?

Сильные ETag (без префикса) различают ресурсы байт-в-байт. Слабые ETag (с префиксом W/) допускают семантическую эквивалентность. Сильные требуются для диапазонных запросов, слабые — для динамически генерируемого контента.

Как ETag помогает в мобильной синхронизации?

ETag сокращает трафик на 80–90%: клиент проверяет актуальность всех ресурсов через If-None-Match, загружая только изменившиеся. Без ETag клиент загружал бы полные данные при каждой синхронизации, расходуя трафик и батарею.

Как реализовать ETag на сервере?

Сервер вычисляет ETag как хеш (MD5, SHA-256) содержимого ответа или использует номер версии записи из базы данных. В Spring Boot достаточно аннотации @Cacheable с etag = true. В Express.js — middleware etag включён по умолчанию.

Итоги

  • ETag — HTTP-заголовок для валидации версий ресурсов, основанный на хеше содержимого или номере версии.
  • Условные запросы — клиент отправляет If-None-Match с сохранённым ETag, сервер отвечает 304 при отсутствии изменений.
  • Типы ETag — сильные (байт-в-байт, для Range запросов) и слабые (семантическая эквивалентность, префикс W/).
  • Преимущество — ETag точнее Last-Modified, так как хеш меняется при любом изменении содержимого независимо от времени.
  • Оптимистичная блокировка — через If-Match ETag предотвращает конфликты Lost Update при конкурентном редактировании ресурса.
  • Дельта-синхронизация — на ETag строятся схемы синхронизации, при которых передаются только изменившиеся ресурсы.
  • Рекомендация — всегда добавляйте ETag в REST API для мобильных приложений. Комбинируйте с Last-Modified для совместимости с CDN и прокси-серверами.

Мы разработаем мобильное приложение под ключ

IT Sectr создаёт приложения для iOS и Android для стартапов и бизнеса с 2017 года. Мы проконсультируем вас и предложим наилучшее решение.

Обсудить проект

Читайте также