ETag (Entity Tag) — HTTP hlavička, která přiřazuje jedinečný identifikátor verze zdroje na serveru a umožňuje klientovi efektivně kontrolovat aktuálnost dat v mezipaměti. Při opakovaném požadavku prohlížeč nebo aplikace odešle uložený ETag a server jej porovná s aktuálním: v případě shody je vrácen stav 304 Not Modified bez těla odpovědi. Podle RFC 7232 (IETF, 2014) snižují podmíněné požadavky s ETagem objem přenášených dat až o 95 % pro často požadované zdroje. To činí hlavičku kriticky důležitou pro výkon mobilních aplikací.
Hlavní body
ETag (Entity Tag) — je HTTP hlavička odpovědi obsahující jedinečný identifikátor konkrétní verze zdroje. Server vypočítá ETag na základě obsahu souboru, jeho metadat nebo čísla revize a předá jej klientovi v odpovědi na požadavek GET. Klient si tento identifikátor uloží a při následných požadavcích na stejný zdroj jej odešle v hlavičce If-None-Match. Pokud se zdroj nezměnil, server odpoví 304 Not Modified a klient použije svou kopii v mezipaměti.
Formát ETagu je definován v RFC 7232 jako řetězec v uvozovkách: "33a64df551425fcc55e4d42a148795d9f25f89d4". Hodnotou může být hash SHA-1 obsahu souboru, inkrementální číslo verze, kombinace inode-číslo-čas pro statické soubory nebo libovolný token generovaný serverem. Jediným požadavkem je, že se hodnota mění při každé změně zdroje a nemění se, pokud zdroj zůstane stejný.
ETag patří mezi mechanismy podmíněných požadavků (conditional requests) — jednu ze základních optimalizací protokolu HTTP. Na rozdíl od bezpodmínečných požadavků, kde server vždy vrací úplnou odpověď, umožňuje podmíněný požadavek klientovi zkontrolovat aktuálnost mezipaměti bez opětovného stahování dat. Podle údajů HTTP Archive (2025) je přibližně 40 % všech HTTP odpovědí 304 Not Modified díky správnému nastavení ETagu a Last-Modified.
ETag se používá v REST API pro optimalizaci načítání kolekcí dat — pokud se seznam objektů nezměnil, klient obdrží 304 bez odesílání celého JSONu. U statických souborů (CSS, JS, obrázky) ETag umožňuje CDN a prohlížečům efektivně kontrolovat aktuálnost mezipaměti. V mobilních aplikacích je ETag kritický pro synchronizaci na pozadí: aplikace kontroluje, zda se data na serveru změnila, a stahuje aktualizace pouze v případě potřeby. To šetří šířku pásma a baterii zařízení.
Úplný cyklus fungování ETagu se skládá ze čtyř kroků. Server vygeneruje ETag při prvním požadavku a vrátí jej v hlavičce odpovědi. Klient si uloží ETag spolu s zdrojem v mezipaměti. Při opakovaném požadavku klient odešle hlavičku If-None-Match s hodnotou uloženého ETagu. Server porovná přijatou hodnotu s aktuálním ETagem zdroje: v případě shody vrátí 304 Not Modified s prázdným tělem, v případě neshody — 200 OK s novým zdrojem a novým ETagem.
// Požadavek klienta s If-None-Match
GET /api/users HTTP/1.1
Host: example.com
If-None-Match: "33a64df551425fcc55e4d42a148795d9f25f89d4"
// Odpověď serveru — zdroj se nezměnil
HTTP/1.1 304 Not Modified
ETag: "33a64df551425fcc55e4d42a148795d9f25f89d4"
V mobilní aplikaci lze tento cyklus implementovat pomocí HTTP klienta s podporou mezipaměti. OkHttp například automaticky spravuje ETag prostřednictvím CacheInterceptoru: ukládá ETag odpovědi a při opakovaném požadavku přidá If-None-Match. Po obdržení 304 OkHttp vrátí data z mezipaměti. OkHttp podporuje ETag bez další konfigurace — stačí povolit cache pomocí OkHttpClient.Builder.cache().
Server může vypočítat ETag různými způsoby: pomocí MD5 nebo SHA hashe obsahu, pomocí čísla revize z databáze (např. updated_at z MySQL), pomocí kombinace inode + mtime + size pro statické soubory (Nginx generuje ETag přesně takto). Pro dynamická API je nejspolehlivější hash obsahu: pokud JSON odpověď změní byť jedno pole, ETag se změní. Výpočet hashe při každém požadavku však zatěžuje CPU — pro systémy s vysokou zátěží je lepší použít inkrementální číslo verze.
RFC 7232 definuje dva typy ETagů: silné (strong) a slabé (weak). Silný ETag znamená, že dvě reprezentace zdroje jsou identické bajt po bajtu — ne liší se ani jeden bit. Slabý ETag (prefix W/) zaručuje pouze sémantickou ekvivalenci: obsah se může lišit na úrovni serializace (mezery, pořadí polí JSON), ale data jsou pro klienta považována za stejná. Slabé ETagy jsou označeny prefixem W/, např. W/"1a2b3c".
Výběr typu ETagu závisí na požadavcích na přesnost porovnání. Pro statické soubory (CSS, JS, obrázky) jsou preferovány silné ETagy — pokud se soubor změnil, klient by měl dostat novou verzi. Pro dynamická API, kde stejný JSON může být serializován s různým pořadím polí nebo formátováním, poskytují slabé ETagy větší flexibilitu: server generuje ETag na základě obchodních dat, nikoli řetězcové reprezentace.
| Typ ETagu | Formát | Záruka | Použití |
|---|---|---|---|
| Strong (silný) | "hash" | Identita bajt po bajtu | Statické soubory, binární zdroje |
| Weak (slabý) | W/"hash" | Sémantická ekvivalence | JSON API, dynamické stránky |
Omezení slabých ETagů: nelze je použít s požadavky na rozsah (Range requests). Pokud klient požaduje část souboru, server musí vrátit silný ETag, aby zaručil, že fragment odpovídá úplnému zdroji. Slabé ETagy takovou záruku neposkytují. V ostatních scénářích jsou slabé ETagy bezpečné a doporučené pro API.
ETag a Last-Modified jsou dvě HTTP hlavičky pro podmíněné požadavky, které se často používají společně. Last-Modified udává datum poslední změny zdroje a pracuje s hlavičkou If-Modified-Since. ETag poskytuje jedinečný identifikátor verze a pracuje s If-None-Match. Každá má své výhody a omezení a kombinace poskytuje maximální efektivitu ukládání do mezipaměti.
Last-Modified je jednodušší na implementaci — server automaticky získá datum ze souborového systému nebo aktualizuje pole updated_at v databázi. Datum však má přesnost na sekundu, což je nedostatečné pro zdroje, které se mění několikrát za sekundu. Kromě toho Last-Modified nerozlišuje různé stavy: pokud je soubor přepsán stejnou verzí, datum se změní, ale obsah ne — klient znovu načte identická data.
ETag je přesnější: mění se pouze při skutečné změně obsahu. Pokud server obnoví předchozí verzi ze zálohy, ETag se změní. Pokud je soubor přepsán stejnými daty — ETag zůstane stejný a klient nebude znovu načítat. Společné použití je doporučeno HTTP specifikací: server vrátí obě hlavičky, klient odešle If-None-Match a If-Modified-Since současně. Pokud alespoň jedna hlavička indikuje změnu — server vrátí nový zdroj.
Podle specifikace má ETag prioritu před Last-Modified. Pokud server obdržel If-None-Match, měl by kontrolovat pouze ETag, ignorujíc If-Modified-Since. Tím se předchází race condition: pokud se zdroj změnil mezi odesláním Last-Modified klientem a kontrolou na serveru, ETag bude novějším ukazatelem. V praxi servery obvykle kontrolují obě hlavičky, ale při neshodě výsledků vítězí ETag.
Nastavení ETagu závisí na typu serveru. Nginx generuje ETag pro statické soubory automaticky na základě inode, mtime a velikosti. Apache používá mechanismus FileETag. Pro dynamické aplikace v Node.js, PHP, Python, Ruby je třeba ETag generovat programově — pomocí hashe odpovědi, čísla verze dat nebo kombinace parametrů požadavku.
func etagMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter,
r *http.Request) {
// Generování ETagu na základě dat
etag := generateETag(r.URL.Path)
w.Header().Set("ETag", etag)
// Kontrola If-None-Match
if r.Header.Get("If-None-Match") == etag {
w.WriteHeader(http.StatusNotModified)
return
}
next.ServeHTTP(w, r)
})
}
Middleware v Go zachytí požadavek, vygeneruje ETag pro požadované URL (například vypočítá hash dat z mezipaměti nebo databáze) a nastaví hlavičku odpovědi. Pokud klient odeslal If-None-Match a ten se shoduje s aktuálním ETagem, server okamžitě vrátí 304 Not Modified, bez volání hlavního handleru. V produkčním prostředí se vyplatí přidat ukládání vypočítaných ETagů do mezipaměti podle URL a parametrů pro snížení zátěže serveru.
V konfiguraci s více servery (round-robin nebo anycast) musí být ETag stejný na všech uzlech pro stejný zdroj. Pokud je ETag generován na základě inode souboru a web běží na několika serverech, hodnoty se budou lišit. Řešení — použití hashe obsahu nebo centralizovaného úložiště verzí (Redis, etcd). Druhý problém — komprese gzip: Nginx mění ETag při zapnuté kompresi, což může způsobit nadměrné 304. Je vyžadováno nastavení gzip_vary on pro synchronizaci ETagu s komprimovaným obsahem.
Často kladené dotazy
Ano, pokud tomu server výslovně nezabránil. ETag nemusí být globálně jedinečný — je jedinečný v rámci konkrétního URL. U statických souborů jsou kolize nepravděpodobné při použití SHA hashe, ale u vlastních generátorů jsou možné duplikáty.
ETag je nejúčinnější pro zdroje, které jsou často požadovány a zřídka se mění: statika, seznamy API, konfigurace. Pro jedinečné stránky, které se načítají jednou (např. stránka potvrzení objednávky), ETag nepřináší výhodu.
CDN bere v úvahu ETag v origin požadavcích pro kontrolu aktuálnosti mezipaměti. Pokud se ETag zdroje na origin změnil, CDN stáhne novou verzi. Cloudflare a Fastly podporují ETag jako standardní mechanismus invalidace mezipaměti na úrovni origin.
RFC 7232 neomezuje délku ETagu, ale servery a proxy mohou příliš dlouhé hodnoty zkrátit nebo ignorovat. Doporučuje se použít hash o délce 20–40 znaků nebo kombinaci identifikátoru verze s kontrolním součtem.
Nejedná se o vzájemně se vylučující mechanismy. Cache-Control určuje politiku ukládání do mezipaměti (jak dlouho uchovávat, komu je povoleno), zatímco ETag je mechanismus validace zdroje v mezipaměti. Optimální konfigurace zahrnuje obě hlavičky dohromady.
Shrnutí
Vyvineme mobilní aplikaci na klíč
IT Sectr vytváří aplikace pro iOS a Android pro startupy a podniky od roku 2017. Poradíme vám a navrhneme nejlepší řešení.
Přečtěte si také