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 + size за статичке датотеке (Nginx генерише ETag управо на овај начин). За динамичке API-је, најпоузданији је хеш садржаја: ако је JSON одговор променио макар једно поље, ETag ће се променити. Међутим, израчунавање хеша при сваком захтеву оптерећује процесор — за системе са високим оптерећењем боље је користити инкрементални број верзије.

Јаки и слаби 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 даје максималну ефикасност кеширања
  • Серверска страна — генерација кроз хеш садржаја, број верзије података или комбинацију параметара
  • Препорука — користити ETag за све API крајње тачке и статичке ресурсе у мобилним апликацијама

Развићемо мобилну апликацију под кључ

IT Sectr креира iOS и Android апликације за стартапе и предузећа од 2017. године. Саветоваћемо вас и предложити најбоље решење.

Разговарајте о пројекту

Прочитајте такође