Last-Modified — este un antet de răspuns HTTP care indică data și ora ultimei modificări a resursei pe server, permițând clientului să execute cereri condiționate prin If-Modified-Since. Dacă resursa nu s-a modificat de la data specificată, serverul returnează 304 Not Modified fără a transmite corpul răspunsului, ceea ce economisește semnificativ traficul. Conform RFC 7232 (IETF, 2014), cererile condiționate cu Last-Modified reduc timpul de încărcare a paginilor cu 30–60% la vizitele repetate. Antetul este suportat automat de majoritatea serverelor HTTP și proxy-urilor.
Principalele puncte
Last-Modified — este un antet HTTP care face parte din grupul antetelor de cereri condiționate (conditional requests). Serverul îl adaugă în răspunsul la GET sau HEAD, indicând data și ora ultimei modificări a resursei solicitate în format HTTP-date: Last-Modified: Wed, 02 Jul 2025 14:30:00 GMT. Clientul (browser, aplicație mobilă, proxy) salvează această dată împreună cu resursa stocată în cache. La o cerere repetată, clientul trimite antetul If-Modified-Since cu aceeași dată, iar serverul o compară cu timpul curent de modificare a resursei.
Protocolul cererilor condiționate cu Last-Modified este definit în RFC 7232 și este suportat de toate serverele HTTP moderne. Formatul datei este strict reglementat — doar GMT (Greenwich Mean Time) fără indicarea fusului orar. Serverul poate returna data în trei formate posibile: RFC 1123 (standard), RFC 850 (învechit) sau ANSI C asctime. În practică, aproape toate serverele folosesc formatul RFC 1123 cu o lungime fixă de 29 de caractere.
Last-Modified aparține categoriei mecanismelor de validare a cache-ului: nu spune clientului dacă poate să stocheze în cache răspunsul, ci oferă un instrument pentru verificarea actualității resursei deja stocate în cache. Politica de stocare în cache este stabilită separat prin antetul Cache-Control. Conform cercetărilor Akamai (2025), configurarea corectă a Last-Modified împreună cu Cache-Control reduce încărcarea serverelor origin cu până la 70% pentru conținutul static.
Antetul Last-Modified a fost definit încă în HTTP/1.0 (RFC 1945, 1996) și a fost unul dintre primele mecanisme de gestionare a cache-ului în web. Până la apariția ETag în HTTP/1.1, a fost singura modalitate de a efectua cereri condiționate. În ciuda vechimii, antetul rămâne actual datorită simplității sale — serverul nu trebuie să calculeze hash-ul conținutului, este suficient să citească timestamp-ul fișierului din sistemul de fișiere sau câmpul updated_at din baza de date.
Ciclul complet include trei etape. La prima cerere, serverul returnează resursa cu antetul Last-Modified și statusul HTTP 200 OK. Clientul stochează în cache răspunsul împreună cu data. La cererea repetată, clientul trimite antetul If-Modified-Since cu data salvată. Serverul compară această dată cu timpul curent de modificare a resursei. Dacă resursa nu s-a modificat — se returnează 304 Not Modified cu corp gol. Dacă s-a modificat — 200 OK cu date noi și un nou Last-Modified.
// Prima cerere — serverul returnează resursa cu data
HTTP/1.1 200 OK
Content-Type: application/json
Last-Modified: Wed, 02 Jul 2025 14:30:00 GMT
[{"id": 1, "name": "Alice"}]
// Cererea repetată — clientul trimite data salvată
GET /api/users HTTP/1.1
Host: example.com
If-Modified-Since: Wed, 02 Jul 2025 14:30:00 GMT
// Răspuns — datele nu s-au modificat
HTTP/1.1 304 Not Modified
Pentru aplicațiile mobile, Last-Modified este deosebit de util la sincronizarea datelor. Aplicația salvează data ultimei actualizări reușite și o trimite serverului în If-Modified-Since. Dacă există mai multe date sau s-au modificat — serverul returnează setul complet. Dacă nu — 304, iar aplicația folosește copia locală. OkHttp și URLSession suportă acest mecanism automat prin sistemele încorporate de stocare în cache.
Pentru fișierele statice, Nginx și Apache preiau data din atributele sistemului de fișiere — mtime (timpul de modificare). Pentru conținutul dinamic, codul serverului trebuie să seteze explicit Last-Modified pe baza logicii de afaceri: câmpul updated_at din baza de date, data ultimului commit în Git, timestamp-ul construirii artefactului. Dacă Last-Modified nu este setat explicit, serverul poate să nu returneze deloc antetul, iar clientul nu va putea efectua cereri condiționate după dată.
Last-Modified și ETag îndeplinesc o sarcină similară — permit clientului să verifice actualitatea cache-ului — dar au diferențe fundamentale. Last-Modified folosește un marcaj temporal, iar ETag — un identificator unic de versiune. Fiecare abordare are scenariile în care este mai eficientă, iar recomandarea specificației HTTP este de a folosi ambele antete împreună.
| Criteriu | Last-Modified | ETag |
|---|---|---|
| Esență | Data ultimei modificări | Identificator unic de versiune |
| Precizie | Până la secundă | Până la bit (hash) |
| Complexitatea implementării | Scăzută — automat din sistemul de fișiere | Medie — necesită calcularea hash-ului |
| Servere în cluster | Problemă: mtime poate diferi între noduri | Stabil cu date identice între noduri |
| Suport pentru intervale | Nu afectează Range requests | Necesită ETag puternic pentru intervale |
| Recomandare | Pentru conținut static și API-uri simple | Pentru API-uri unde verificarea exactă este importantă |
Principalul avantaj al Last-Modified este simplitatea. Serverul nu trebuie să calculeze hash-ul conținutului, ceea ce economisește resursele CPU la fiecare cerere. Pentru proiectele cu încărcare mare care livrează fișiere statice sau date cu marcaje temporale clare, Last-Modified rămâne alegerea optimă. ETag, în schimb, oferă o precizie absolută — modificarea unei singure litere în răspunsul JSON va schimba ETag-ul, dar poate să nu schimbe data (dacă fișierul a fost suprascris cu aceeași versiune).
Specificația recomandă returnarea ambelor antete simultan. Serverul include atât Last-Modified, cât și ETag în răspunsul 200 OK. Clientul trimite ambele antete condiționate — If-Modified-Since și If-None-Match. Serverul verifică mai întâi ETag (are prioritate), apoi Last-Modified. Dacă cel puțin unul semnalizează o modificare — se returnează răspunsul complet. Aceasta oferă o flexibilitate maximă: ETag asigură precizia, iar Last-Modified — verificarea de rezervă pentru clienții care nu suportă ETag.
Configurarea Last-Modified depinde de tipul serverului. Pentru Nginx și Apache, fișierelor statice li se setează Last-Modified automat pe baza mtime. Pentru aplicațiile dinamice, antetul trebuie setat în codul serverului. Să analizăm configurarea pe platformele populare.
// Express.js — setarea Last-Modified
app.get("/api/users", async (req, res) => {
const updatedAt = await getLastUpdate()
const ifModifiedSince = req.get("If-Modified-Since")
// Verificarea 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)
})
În exemplul pe Express.js, serverul obține data ultimei actualizări a datelor din bază, verifică If-Modified-Since de la client și, dacă cache-ul este actual, returnează 304. Dacă datele s-au modificat — setează un nou Last-Modified și returnează răspunsul complet. toUTCString() convertește data în formatul HTTP necesar. în producție, merită să adăugați stocarea în cache a updatedAt în Redis pentru a nu executa o interogare a bazei de date la fiecare accesare.
Nginx setează automat Last-Modified pentru fișierele statice pe baza timpului ultimei modificări a fișierului. Dezactivarea sau modificarea comportamentului se poate face prin directiva etag (dezactivarea ETag) sau prin modulul ngx_http_headers_module. Pentru cererile proxy către backend, Last-Modified este transmis din răspunsul upstream fără modificări. Important: dacă backend-ul nu returnează Last-Modified, Nginx nu îl va adăuga automat pentru răspunsurile dinamice.
Last-Modified are câteva limitări cunoscute. Principala este precizia până la secundă. Dacă resursa s-a modificat de două ori în decurs de o secundă, clientul poate pierde noua versiune. în practică, acesta este un scenariu rar, dar pentru actualizări de înaltă frecvență (fluxuri de cotații, chat-uri) se recomandă ETag. A doua limitare este problema clusterizării: pe servere diferite, fișierul poate avea un mtime diferit din cauza copierii sau implementării, ceea ce face ca Last-Modified să fie inconsistent.
A treia limitare — procesarea If-Modified-Since cu precizie până la secundă poate duce la cereri inutile la interogarea frecventă a serverului. Dacă clientul trimite If-Modified-Since la fiecare 500 ms, serverul returnează de fiecare dată 200 OK, deoarece data nu s-a modificat, dar resursa a fost de fapt deja actualizată. Soluția este combinarea cu ETag: ETag va detecta modificarea în decurs de o secundă, iar Last-Modified va rămâne ca rezervă.
A patra problemă — Last-Modified nu diferențiază diferitele versiuni ale aceleiași resurse cu aceeași dată. Dacă fișierul a fost restaurat dintr-o copie de rezervă și mtime-ul său coincide cu originalul, clientul nu va observa că conținutul s-a modificat. ETag rezolvă această problemă: hash-ul conținutului se va schimba garantat la orice modificare a datelor, indiferent de marcajul temporal. Pentru datele critice, folosiți întotdeauna ambele antete.
Întrebări frecvente
Doar GMT (Greenwich Mean Time) în format RFC 1123: ziua săptămânii, data, luna, anul, orele:minutele:secundele. Exemplu: Wed, 02 Jul 2025 14:30:00 GMT. Fusul orar este întotdeauna GMT, alte formate nu sunt permise.
Tehnic poate, dar aceasta încalcă RFC 7232. Dacă serverul returnează o dată în viitor, clienții nu vor actualiza resursa până la sosirea acelei date. O astfel de configurație este considerată eroare — data trebuie să fie în trecut sau în prezent.
Nu, cererile condiționate If-Modified-Since funcționează doar cu GET și HEAD. Cererile POST nu sunt stocate în cache și nu folosesc validarea după dată. Pentru verificarea actualității datelor în POST, folosiți ETag sau mecanisme personalizate.
Cache-Control stabilește politica de stocare în cache (timpul maxim de păstrare, cine poate stoca în cache), iar Last-Modified este mecanismul de validare a cache-ului expirat. După expirarea max-age, clientul trimite If-Modified-Since pentru a verifica actualitatea.
Verificați dacă serverul setează într-adevăr antetul din sursa actuală — baza de date, sistemul de fișiere sau API. Pentru răspunsurile dinamice, asigurați-vă că apelați explicit res.setHeader(„Last-Modified”, ...) în codul handler-ului.
Concluzii
Vom dezvolta o aplicație mobilă la cheie
IT Sectr creează aplicații iOS și Android pentru startup-uri și afaceri din 2017. Vă vom consilia și vă vom propune cea mai bună soluție.
Citiți și