ETag: що це, механізм кешування та налаштування заголовка

Автор: IT Sectr Опубліковано: 2026-03-09 Час читання: 8 хв

ETag (Entity Tag) — це HTTP-заголовок, який присвоює унікальний ідентифікатор версії ресурсу на сервері, дозволяючи клієнту ефективно перевіряти актуальність кешованих даних. При повторному запиті браузер або застосунок надсилає збережений ETag, і сервер порівнює його з поточним: при збігу повертається статус 304 Not Modified без тіла відповіді. За даними RFC 7232 (IETF, 2014), умовні запити з ETag скорочують обсяг переданих даних до 95% для ресурсів, до яких часто звертаються. Це робить заголовок критично важливим для продуктивності мобільних застосунків.

Головне

  • ETag — HTTP-заголовок з унікальним ідентифікатором версії ресурсу для умовних запитів і кешування
  • Принцип роботи — сервер генерує хеш контенту або номер версії, клієнт надсилає його в заголовку If-None-Match
  • Сильні та слабкі ETag — сильні (контент ідентичний байт-в-байт) і слабкі (контент семантично еквівалентний, префікс W/)
  • 304 Not Modified — відповідь сервера при збігу ETag, що економить трафік і прискорює завантаження
  • ETag vs Last-Modified — ETag точніший (хеш контенту), Last-Modified простіший (дата), разом дають максимальну ефективність

Що таке ETag?

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

Формат ETag визначений у RFC 7232 як рядок у лапках: "33a64df551425fcc55e4d42a148795d9f25f89d4". Значення може бути хешем SHA-1 вмісту файлу, інкрементальним номером версії, комбінацією inode-номер-час для статичних файлів або довільним токеном, який генерує сервер. Єдина вимога — значення повинно змінюватися при будь-якій зміні ресурсу і не змінюватися, якщо ресурс залишився незмінним.

ETag належить до механізмів умовних запитів (conditional requests) — однієї з базових оптимізацій HTTP-протоколу. На відміну від безумовних запитів, де сервер завжди повертає повну відповідь, умовний запит дозволяє клієнту перевірити актуальність кешу без повторного завантаження даних. За даними HTTP Archive (2025), близько 40% усіх HTTP-відповідей — це 304 Not Modified завдяки правильному налаштуванню ETag і Last-Modified.

Де застосовується ETag

ETag використовується в REST API для оптимізації завантаження колекцій даних — якщо список об'єктів не змінився, клієнт отримує 304 без передачі всього JSON. У статичних файлах (CSS, JS, зображення) ETag дозволяє CDN і браузерам ефективно перевіряти актуальність кешу. У мобільних застосунках ETag критичний для фонової синхронізації: застосунок перевіряє, чи змінилися дані на сервері, і завантажує оновлення лише при необхідності. Це економить трафік і батарею пристрою.

Як працює ETag?

Повний цикл роботи ETag складається з чотирьох кроків. Сервер генерує ETag при першому запиті та повертає його в заголовку відповіді. Клієнт зберігає ETag разом із кешованим ресурсом. При повторному запиті клієнт надсилає заголовок If-None-Match зі значенням збереженого ETag. Сервер порівнює отримане значення з поточним ETag ресурсу: при збігу повертає 304 Not Modified з порожнім тілом, при незбігу — 200 OK з новим ресурсом і новим ETag.

http
// Запит клієнта з If-None-Match
GET /api/users HTTP/1.1
Host: example.com
If-None-Match: "33a64df551425fcc55e4d42a148795d9f25f89d4"

// Відповідь сервера — ресурс не змінився
HTTP/1.1 304 Not Modified
ETag: "33a64df551425fcc55e4d42a148795d9f25f89d4"

У мобільному застосунку цей цикл може бути реалізований через HTTP-клієнт з підтримкою кешування. OkHttp, наприклад, автоматично керує ETag через CacheInterceptor: він зберігає ETag відповіді та при повторному запиті додає If-None-Match. При отриманні 304 OkHttp повертає кешовані дані. OkHttp підтримує ETag без додаткового налаштування — достатньо ввімкнути кеш через OkHttpClient.Builder.cache().

Генерація ETag на сервері

Сервер може обчислювати ETag різними способами: через MD5- або SHA-хеш вмісту, через номер ревізії з бази даних (наприклад, updated_at з MySQL), через комбінацію inode + mtime + розмір для статичних файлів (Nginx генерує ETag саме так). Для динамічних API найнадійніший хеш контенту: якщо JSON-відповідь змінила хоча б одне поле, ETag зміниться. Однак обчислення хешу при кожному запиті навантажує CPU — для високонавантажених систем краще використовувати інкрементальний номер версії.

Сильні та слабкі ETag

RFC 7232 визначає два типи ETag: сильні (strong) і слабкі (weak). Сильний ETag означає, що два представлення ресурсу ідентичні байт-в-байт — жоден біт не відрізняється. Слабкий ETag (префікс W/) гарантує лише семантичну еквівалентність: вміст може відрізнятися на рівні серіалізації (пробіли, порядок полів JSON), але дані для клієнта вважаються однаковими. Слабкі ETag позначаються префіксом W/, наприклад W/"1a2b3c".

Вибір типу ETag залежить від вимог до точності порівняння. Для статичних файлів (CSS, JS, зображення) переважні сильні ETag — якщо файл змінився, клієнт повинен отримати нову версію. Для динамічних API, де один і той самий JSON може бути серіалізований з різним порядком полів або форматуванням, слабкі ETag дають більше гнучкості: сервер генерує ETag на основі бізнес-даних, а не рядкового представлення.

Тип ETagФорматГарантіяЗастосування
Strong (сильний)"хеш"Ідентичність байт-в-байтСтатичні файли, бінарні ресурси
Weak (слабкий)W/"хеш"Семантична еквівалентністьJSON API, динамічні сторінки

Обмеження слабких ETag: вони не можуть використовуватися з діапазонними запитами (Range requests). Якщо клієнт запитує частину файлу, сервер повинен повернути сильний ETag, щоб гарантувати, що фрагмент відповідає повному ресурсу. Слабкі ETag не забезпечують такої гарантії. В інших сценаріях слабкі ETag безпечні та рекомендовані для API.

ETag vs Last-Modified

ETag і Last-Modified — два HTTP-заголовки для умовних запитів, які часто використовуються разом. Last-Modified вказує дату останньої зміни ресурсу та працює із заголовком If-Modified-Since. ETag надає унікальний ідентифікатор версії та працює з If-None-Match. Кожен має свої переваги та обмеження, а комбінація дає максимальну ефективність кешування.

Last-Modified простіший у реалізації — сервер автоматично отримує дату з файлової системи або оновлює поле updated_at у базі даних. Однак дата має точність до секунди, що недостатньо для ресурсів, які змінюються кілька разів на секунду. Крім того, Last-Modified не розрізняє різні стани: якщо файл перезаписано тією ж версією, дата змінилася, а контент — ні, клієнт перезавантажить ідентичні дані.

ETag точніший: він змінюється лише при реальній зміні контенту. Якщо сервер відновив попередню версію з бекапу, ETag зміниться. Якщо файл перезаписано тими самими даними — ETag залишиться незмінним, і клієнт не буде перезавантажувати. Спільне використання рекомендовано HTTP-специфікацією: сервер повертає обидва заголовки, клієнт надсилає If-None-Match і If-Modified-Since одночасно. Якщо хоча б один заголовок показує зміну — сервер повертає новий ресурс.

Пріоритет заголовків

За специфікацією, ETag має пріоритет над Last-Modified. Якщо сервер отримав If-None-Match, він повинен перевіряти тільки ETag, ігноруючи If-Modified-Since. Це запобігає race condition: якщо ресурс змінився між надсиланням клієнтом Last-Modified і перевіркою на сервері, ETag буде більш свіжим індикатором. На практиці сервери зазвичай перевіряють обидва заголовки, але при неспівпадінні результатів перемагає ETag.

Реалізація ETag на сервері

Налаштування ETag залежить від типу сервера. Nginx генерує ETag для статичних файлів автоматично на основі inode, mtime та розміру. Apache використовує механізм FileETag. Для динамічних застосунків на Node.js, PHP, Python, Ruby ETag потрібно генерувати програмно — через хеш відповіді, номер версії даних або комбінацію параметрів запиту.

go
func etagMiddleware(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter,
        r *http.Request) {
        // Генерація ETag на основі даних
        etag := generateETag(r.URL.Path)
        w.Header().Set("ETag", etag)

        // Перевірка If-None-Match
        if r.Header.Get("If-None-Match") == etag {
            w.WriteHeader(http.StatusNotModified)
            return
        }
        next.ServeHTTP(w, r)
    })
}

Middleware на Go перехоплює запит, генерує ETag для запитаного URL (наприклад, обчислює хеш даних із кешу або БД) і встановлює заголовок відповіді. Якщо клієнт надіслав If-None-Match і він збігається з поточним ETag, сервер повертає 304 Not Modified одразу, без виклику основного обробника. У продакшені варто додати кешування обчислених ETag за URL і параметрами для зниження навантаження на сервер.

Проблеми та підводні камені

У багатосерверній конфігурації (round-robin або anycast) ETag повинен бути однаковим на всіх нодах для одного й того самого ресурсу. Якщо ETag генерується на основі inode файлу, а сайт розгорнуто на кількох серверах, значення відрізнятимуться. Рішення — використовувати хеш вмісту або централізоване зберігання версій (Redis, etcd). Друга проблема — gzip-стиснення: Nginx змінює ETag при ввімкненні стиснення, що може викликати надлишкові 304. Потрібне налаштування gzip_vary on для синхронізації ETag із стисненим контентом.

Поширені запитання

Чи може ETag бути однаковим для різних ресурсів?

Так, якщо сервер явно цього не запобіг. ETag не зобов'язаний бути глобально унікальним — він унікальний у межах конкретного URL. Для статичних файлів колізії малоймовірні при використанні SHA-хешу, але для саморобних генераторів можливі дублікати.

Чи потрібно налаштовувати ETag для кожного ресурсу?

ETag найбільш ефективний для ресурсів, які запитуються багаторазово і рідко змінюються: статика, API-списки, конфігурації. Для унікальних сторінок, які завантажуються один раз (наприклад, сторінка підтвердження замовлення), ETag не дає переваги.

Як ETag працює з CDN?

CDN враховує ETag в origin-запитах для перевірки актуальності кешу. Якщо ETag ресурсу на origin змінився, CDN завантажує нову версію. Cloudflare і Fastly підтримують ETag як стандартний механізм інвалідації кешу на рівні origin.

Чи може ETag бути довшим за 255 символів?

RFC 7232 не обмежує довжину ETag, але сервери та проксі можуть урізати або ігнорувати надто довгі значення. Рекомендується використовувати хеш довжиною 20–40 символів або комбінацію ідентифікатора версії з контрольною сумою.

Що вибрати: ETag чи Cache-Control?

Це не взаємовиключні механізми. Cache-Control визначає політику кешування (скільки зберігати, кому дозволено), а ETag — механізм валідації кешованого ресурсу. Оптимальна конфігурація включає обидва заголовки разом.

Підсумки

  • ETag — HTTP-заголовок з унікальним ідентифікатором версії ресурсу для умовних запитів та ефективного кешування
  • Принцип — клієнт надсилає If-None-Match зі збереженим ETag, сервер відповідає 304 при збігу
  • Сильні ETag — ідентичність байт-в-байт для статичних файлів, слабкі — семантична еквівалентність для API
  • ETag точніший за Last-Modified — відстежує контент, а не дату, і змінюється лише при реальних змінах
  • Спільне використання з Last-Modified дає максимальну ефективність кешування
  • Server-Side — генерація через хеш контенту, номер версії даних або комбінацію параметрів
  • Рекомендація — використовувати ETag для всіх API-ендпоінтів і статичних ресурсів у мобільних застосунках

Ми розробимо мобільний застосунок під ключ

IT Sectr створює застосунки для iOS та Android для стартапів і бізнесу з 2017 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.

Обговорити проект

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