Last-Modified — HTTP заглавље одговора који указује датум и време последње измене ресурса на серверу, омогућући клијенту да извршава условне захтеве путем If-Modified-Since. Ако се ресурс није променио од наведеног датума, сервер враћа 304 Not Modified без преношења тела одговора, што значајно штеди проток. Према RFC 7232 (IETF, 2014), условни захтеви са Last-Modified скраћују време учитавања страница за 30–60% при поновним посетама. Заглавље се аутоматски подржава од стране већине HTTP сервера и проксија.
Главно
Last-Modified — је HTTP заглавље које спада у групу заглавља условних захтева (conditional requests). Сервер га додаје у одговор на GET или HEAD, наводећи датум и време последње измене затраженог ресурса у HTTP-date формату: Last-Modified: Wed, 02 Jul 2025 14:30:00 GMT. Клијент (претраживач, мобилна апликација, прокси) чува овај датум заједно са кешираним ресурсом. При поновном захтеву, клијент шаље заглавље If-Modified-Since са истим датумом, а сервер га упоредђује са тренутним временом измене ресурса.
Протокол условних захтева са Last-Modified је дефинисан у RFC 7232 и подржава га сви модерни HTTP сервери. Формат датума је строго регулисан — само GMT (Greenwich Mean Time) без наводења временске зоне. Сервер може да врати датум у три могућа формата: RFC 1123 (стандардни), RFC 850 (застарео) или ANSI C asctime. У пракси, готово сви сервери користе RFC 1123 формат са фиксном дужином од 29 знакова.
Last-Modified спада у категорију механизама за валидацију кеша: он не каже клијенту да ли може да кешира одговор, већ пружа алат за проверу актуелности већ кешираног ресурса. Политика кеширања се поставља одвојено путем заглавља Cache-Control. Према истраживању Akamai (2025), исправно подешавање Last-Modified заједно са Cache-Control смањује оптерећење origin сервера до 70% за статички садржај.
Заглавље Last-Modified је дефинисано још у HTTP/1.0 (RFC 1945, 1996) и било је један од првих механизама за управљање кешом у вебу. Пре појаве ETag-а у HTTP/1.1, био је једини начин за извршавање условних захтева. Упркос старости, заглавље остаје актуелно захваљујући својој једноставности — сервер не мора да рачуна хеш садржаја, довољно је да прочита тимстемп датотеке из датотечног система или поље updated_at из базе података.
Пун циклус укључује три фазе. При првом захтеву, сервер враћа ресурс са заглављем Last-Modified и HTTP статусом 200 OK. Клијент кешира одговор заједно са датумом. При поновном захтеву, клијент шаље заглавље If-Modified-Since са сачуваним датумом. Сервер упоредђује овај датум са тренутним временом измене ресурса. Ако се ресурс није променио — враћа се 304 Not Modified са празним телом. Ако је промењен — 200 OK са новим подацима и новим Last-Modified.
// Први захтев — сервер враћа ресурс са датумом
HTTP/1.1 200 OK
Content-Type: application/json
Last-Modified: Wed, 02 Jul 2025 14:30:00 GMT
[{"id": 1, "name": "Alice"}]
// Поновни захтев — клијент шаље сачувани датум
GET /api/users HTTP/1.1
Host: example.com
If-Modified-Since: Wed, 02 Jul 2025 14:30:00 GMT
// Одговор — подаци се нису променили
HTTP/1.1 304 Not Modified
За мобилне апликације, Last-Modified је посебно користан при синхронизацији података. Апликација чува датум последње успешне ажурирања и шаље га серверу у If-Modified-Since. Ако има више података или су се променили — сервер враћа пун скуп. Ако нијсу — 304, и апликација користи локалну копију. OkHttp и URLSession аутоматски подржавају овај механизам кроз уграђене системе кеширања.
За статичке датотеке, Nginx и Apache узимају датум из атрибута датотечног система — mtime (време модификације). За динамички садржај, код сервера мора експлицитно да постави Last-Modified на основу пословне логике: поље updated_at из базе података, датум последњег комита у Git-у, тимстемп изградње артефакта. Ако Last-Modified није експлицитно постављен, сервер може да не врати заглавље уопште, и клијент неће моћи да извршава условне захтеве по датуму.
Last-Modified и ETag обављају сличан задатак — омогућућу клијенту да провери актуелност кеша — али имају принципијелне разлике. Last-Modified користи временску ознаку, ETag — јединствени идентификатор верзије. Сваки приступ има сценарије у којима је ефикаснији, а препорука HTTP спецификације је да се оба заглавља користе заједно.
| Критеријум | Last-Modified | ETag |
|---|---|---|
| Суштина | Датум последње измене | Јединствени идентификатор верзије |
| Прецизност | До секунде | До бита (хеш) |
| Сложеност имплементације | Ниска — аутоматски из датотечног система | Средња — захтева рачунање хеша |
| Кластерисани сервери | Проблем: mtime се може разликовати на чворовима | Стабилан код истих података на чворовима |
| Подршка опсега | Не утиче на Range requests | Захтева јак ETag за опсеге |
| Препорука | За статику и једноставна API | За API где је важна прецизна провера |
Главна предност Last-Modified-а је једноставност. Сервер не мора да рачуна хеш садржаја, што штеди CPU ресурсе при сваком захтеву. За пројекте са високим оптерећењем који испоручују статичке датотеке или податке са јасним временским ознакама, Last-Modified остаје оптималан избор. ETag пак пружа апсолутну прецизност — промена једног слова у JSON одговору промениће ETag, али можда неће променити датум (ако је датотека преписана истом верзијом).
Спецификација препоручује враћање оба заглавља истовремено. Сервер укључује и Last-Modified и ETag у одговор 200 OK. Клијент шаље оба условна заглавља — If-Modified-Since и If-None-Match. Сервер прво проверава ETag (има приоритет), затим Last-Modified. Ако бар један сигнализира промену — враћа се пун одговор. Ово пружа максималну флексибилност: ETag осигурава прецизност, Last-Modified — резервну проверу за клијенте који не подржавају ETag.
Подешавање Last-Modified зависи од типа сервера. За Nginx и Apache, статичким датотекама Last-Modified се поставља аутоматски на основу mtime. За динамичке апликације, заглавље се мора поставити у коду сервера. Погледајмо подешавање на популарним платформама.
// Express.js — постављање Last-Modified
app.get("/api/users", async (req, res) => {
const updatedAt = await getLastUpdate()
const ifModifiedSince = req.get("If-Modified-Since")
// Провера If-Modified-Since
if (ifModifiedSince && new Date(ifModifiedSince)
>= updatedAt) {
return res.status(304).end()
}
const users = await getUsers()
res.set("Last-Modified", updatedAt.toUTCString())
res.json(users)
})
У примеру на Express.js, сервер добија датум последње ажурирања података из базе, проверава If-Modified-Since од клијента и ако је кеш ажуран враћа 304. Ако су се подаци променили — поставља нови Last-Modified и враћа пун одговор. toUTCString() претвара датум у потребан HTTP формат. У производном окружењу вреди додати кеширање updatedAt у Redis-у да се избегне извршавање упита бази података при сваком приступу.
Nginx аутоматски поставља Last-Modified за статичке датотеке на основу времена последње измене датотеке. Онемогућити или изменити понашање може се директивом etag (искључивање ETag-а) или путем модула ngx_http_headers_module. За proxy захтеве ка backend-у, Last-Modified се преноси из upstream одговора без промена. Важно: ако backend не враћа Last-Modified, Nginx га неће аутоматски додати за динамичке одговоре.
Last-Modified има неколико познатих ограничења. Главно је прецизност до секунде. Ако се ресурс променио два пута у једној секунди, клијент може да пропусти нову верзију. У пракси, ово је редак сценаријум, али за ажурирања високе фреквенције (федови котација, четови) препоручује се ETag. Друго ограничење је проблем кластеризације: на различитим серверима датотека може имати различит mtime због копирања или постављања, због чега Last-Modified постаје неконзистентан.
Треће ограничење — обрада If-Modified-Since са прецизношћу до секунде може довести до непотребних захтева при честом испитивању сервера. Ако клијент шаље If-Modified-Since сваких 500 ms, сервер сваки пут враћа 200 OK, јер се датум није променио, али је ресурс заправо већ ажуриран. Решење је комбинација са ETag: ETag ће уловити промену у оквиру секунде, а Last-Modified ће остати као резерва.
Четврти проблем — Last-Modified не разликује различите верзије истог ресурса са истом датумом. Ако је датотека враћена из резервне копије и јен mtime се поклапа са оригиналом, клијент неће приметити да се садржај променио. ETag решава овај проблем: хеш садржаја ће се гарантовано променити при свакој промени података, без обзира на временску ознаку. За критичне податке увијек користите оба заглавља.
Често постављана питања
Само GMT (Greenwich Mean Time) у RFC 1123 формату: дан у недељи, број, месец, година, сати:минути:секунде. Примјер: Wed, 02 Jul 2025 14:30:00 GMT. Временска зона је увијек GMT, други формати нису дозвољени.
Технички може, али то крши RFC 7232. Ако сервер врати датум у будућности, клијенти неће ажурирати ресурс до наступа тог датума. Таква конфигурација се сматра грешком — датум мора бити у прошлости или садашњости.
Не, условни захтеви If-Modified-Since раде само са GET и HEAD. POST захтеви се не кеширају и не користе валидацију по датуму. За проверу ажурности података за POST користите ETag или прилагођене механизме.
Cache-Control одређује политику кеширања (макс. време чувања, ко може да кешира), а Last-Modified је механизам за валидацију застарелог кеша. Након истека max-age, клијент шаље If-Modified-Since за проверу ажурности.
Проверите да ли сервер заиста поставља заглавље из ажурног извора — базе података, датотечног система или API. За динамичке одговоре, осигурајте се да експлицитно позивате res.setHeader(„Last-Modified”, ...) у коду руковатеља.
Закључак
Развићемо мобилну апликацију под кључ
IT Sectr креира iOS и Android апликације за стартапе и предузећа од 2017. године. Саветоваћемо вас и предложити најбоље решење.
Прочитајте такође