ETag (Entity Tag) — HTTP заглавие, което присвоява уникален идентификатор на версията на ресурс на сървъра, позволявайки на клиента ефективно да проверява актуалността на кешираните данни. При повторно заявка браузърът или приложението изпраща запазения ETag, а сървърът го сравнява с текущия: при съвпадение се върща статус 304 Not Modified без тяло на отговора. Според RFC 7232 (IETF, 2014), условните заявки с ETag намаляват обема на предаваните данни до 95% за често заявявани ресурси. Това прави заглавието критично важно за производителността на мобилните приложения.
Основни позиции
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 се използва в REST API за оптимизиране на зареждането на колекции от данни — ако списъкът на обектите не е променен, клиентът получава 304, без да изпраща цялия JSON. В статични файлове (CSS, JS, изображения) ETag позволява на CDN и браузърите ефективно да проверяват актуалността на кеша. В мобилните приложения ETag е критичен за фонова синхронизация: приложението проверява дали данните на сървъра са се променили и изтегля актуализации само при необходимост. Това икономи трафик и батерията на устройството.
Пълният цикъл на работа на ETag се състои от четири стъпки. Сървърът генерира ETag при първата заявка и го върща в заглавието на отговора. Клиентът запазва ETag заедно с кеширания ресурс. При повторна заявка клиентът изпраща заглавие If-None-Match със стойността на запазения ETag. Сървърът сравнява получената стойност с текущия ETag на ресурса: при съвпадение върща 304 Not Modified с празно тяло, при несъвпадение — 200 OK с нов ресурс и нов ETag.
// Заявка на клиента с 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 по различни начини: чрез MD5 или SHA хеш на съдържанието, чрез номер на ревизия от базата данни (например, updated_at от MySQL), чрез комбинация inode + mtime + size за статични файлове (Nginx генерира ETag именно по този начин). За динамични API най-надежден е хешът на съдържанието: ако JSON отговорът промени дори едно поле, 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 и 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 зависи от типа на сървъра. Nginx генерира ETag за статични файлове автоматично на базата на inode, mtime и размер. Apache използва механизма FileETag. За динамични приложения в Node.js, PHP, Python, Ruby, ETag трябва да се генерира програмно — чрез хеш на отговора, номер на версията на данните или комбинация от параметри на заявката.
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, без да вика основния handler. В производствена среда се препоръчва добавяне на кеширане на изчислените ETag по URL и параметри за намаляване натоварването на сървъра.
В многосървърна конфигурация (round-robin или anycast) ETag трябва да бъде еднакъв на всички назли за един и същ ресурс. Ако ETag се генерира на базата на inode на файла, а сайтът работи на няколко сървъра, стойностите ще се различават. Решението — използване на хеш на съдържанието или централизирано съхранение на версии (Redis, etcd). Вторият проблем — gzip компресия: Nginx променя ETag, когато компресията е включена, което може да причини прекалени 304. Необходимо е настройката на gzip_vary on за синхронизация на ETag с компресираното съдържание.
Често задавани въпроси
Да, ако сървърът явно не е предотвратил това. ETag не трябва да бъде глобално уникален — той е уникален в рамките на конкретен URL. За статични файлове колизиите са малко вероятни при използване на SHA хеш, но за собствени генератори са възможни дубликати.
ETag е най-ефективен за ресурси, които се заявяват многократно и редко се променят: статика, API списъци, конфигурации. За уникални страници, които се зареждат един път (например, страницата за потвърждаване на поръчка), ETag не предоставя предимство.
CDN взема предвид ETag в origin заявките за проверка на актуалността на кеша. Ако ETag на ресурса на origin се промени, CDN изтегля новата версия. Cloudflare и Fastly поддържат ETag като стандартен механизъм за анулиране на кеша на ниво origin.
RFC 7232 не ограничава дължината на ETag, но сървърите и проксита могат да съкратят или игнорират прекалено дълги стойности. Препоръчва се използването на хеш с дължина 20–40 знака или комбинация от идентификатор на версия с контролна сума.
Това не са взаимно изключващи се механизми. Cache-Control определя политиката на кеширане (колко дълго да се пази, на кого е разрешено), а ETag е механизъм за валидация на кеширания ресурс. Оптималната конфигурация включва и двете заглавия заедно.
Обобщение
Ще разработим мобилно приложение под ключ
IT Sectr създава iOS и Android приложения за стартъпи и бизнеси от 2017 г. Ще ви консултираме и ще предложим най-доброто решение.
Прочетете също