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 от базата данни, датата на последния commit в Git, времевия печат на изграждане на артефакта. Ако Last-Modified не е настроен експлицитно, сървърът може изобщо да не върне заглавието, и клиентът няма да може да изпълнява условни заявки по дата.
Last-Modified и ETag изпълняват подобна задача — позволяват на клиента да провери актуалността на кеша — но имат принципни разлики. Last-Modified използва времеви печат, ETag — уникален идентификатор на версията. Всяка пробстранецгование има сценарии, където е по-ефективно, и препоръката на HTTP спецификацията е да се използват и двете заглавия заедно.
| Критерий | Last-Modified | ETag |
|---|---|---|
| Същност | Дата на последна промяна | Уникален идентификатор на версия |
| Точност | До секунда | До бит (hash) |
| Сложност на имплементацията | Ниска — автоматично от файловата система | Средна — изисква изчисляване на хеш |
| Кластърни сървъри | Проблем: mtime може да се различава на възлите | Стабилен при еднакви данни на възлите |
| Поддържка на диапазони | Не влияе на Range заявки | Изисква силен 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 решава този проблем: hash на съдържанието гарантирано ще се промени при всяка промяна на данните, независимо от времевия печат. За критични данни винаги използвайте и двете заглавия.
Често задавани въпроси
Само 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“", ...) в кода на handler-а.
Заключение
Ще разработим мобилно приложение под ключ
IT Sectr създава iOS и Android приложения за стартъпи и бизнеси от 2017 г. Ще ви консултираме и ще предложим най-доброто решение.
Прочетете също