Last-Modified — essenza, meccanismo e configurazione dell’header della data di modifica

Autore: IT Sectr Pubblicato: 2026-03-09 Tempo di lettura: 9 min

Last-Modified è un header di risposta HTTP che indica la data e l’ora dell’ultima modifica di una risorsa sul server, consentendo al client di effettuare richieste condizionali tramite If-Modified-Since. Se la risorsa non è cambiata dalla data specificata, il server restituisce 304 Not Modified senza inviare il corpo della risposta, risparmiando notevolmente banda. Secondo RFC 7232 (IETF, 2014), le richieste condizionali con Last-Modified riducono i tempi di caricamento delle pagine del 30-60% nelle visite successive. L’header è supportato automaticamente dalla maggior parte dei server HTTP e proxy.

Punti Chiave

  • Last-Modified — header HTTP con la data dell’ultima modifica della risorsa per richieste condizionali If-Modified-Since
  • 304 Not Modified — risposta del server se la risorsa non è cambiata; il client usa la sua copia in cache
  • Precisione al secondo — limite dell’header: modifiche entro un secondo possono passare inosservate
  • Lavora insieme a ETag — il server restituisce entrambi gli header, il client invia entrambe le richieste condizionali
  • Generazione automatica — Nginx e Apache impostano Last-Modified per i file statici dal filesystem

Cos’è Last-Modified?

Last-Modified è un header HTTP che appartiene al gruppo degli header di richiesta condizionale. Il server lo aggiunge a una risposta GET o HEAD, indicando la data e l’ora dell’ultima modifica della risorsa richiesta nel formato HTTP-date: Last-Modified: Wed, 02 Jul 2025 14:30:00 GMT. Il client (browser, app mobile, proxy) memorizza questa data insieme alla risorsa in cache. In una richiesta successiva, il client invia l’header If-Modified-Since con la stessa data e il server la confronta con l’ora corrente di modifica della risorsa.

Il protocollo delle richieste condizionali con Last-Modified è definito in RFC 7232 ed è supportato da tutti i server HTTP moderni. Il formato della data è strettamente regolamentato — solo GMT (Greenwich Mean Time) senza indicazione del fuso orario. Il server deve restituire la data in tre formati possibili: RFC 1123 (standard), RFC 850 (obsoleto) o ANSI C asctime. In pratica, quasi tutti i server utilizzano il formato RFC 1123 con una lunghezza fissa di 29 caratteri.

Last-Modified appartiene alla categoria dei meccanismi di validazione della cache: non dice al client se la risposta può essere memorizzata nella cache, ma fornisce uno strumento per verificare l’attualità di una risorsa già in cache. La politica di caching viene definita separatamente tramite l’header Cache-Control. Secondo uno studio di Akamai (2025), una corretta configurazione di Last-Modified insieme a Cache-Control riduce il carico sui server di origine fino al 70% per i contenuti statici.

Quando è apparso Last-Modified?

L’header Last-Modified è stato definito già in HTTP/1.0 (RFC 1945, 1996) ed è diventato uno dei primi meccanismi di gestione della cache sul web. Prima dell’arrivo di ETag in HTTP/1.1, era l’unico modo per effettuare richieste condizionali. Nonostante l’età, l’header rimane rilevante grazie alla sua semplicità — il server non deve calcolare un hash del contenuto, gli basta leggere il timestamp del file dal filesystem o il campo updated_at dal database.

Come funziona Last-Modified?

Il ciclo completo comprende tre fasi. Alla prima richiesta, il server restituisce la risorsa con l’header Last-Modified e lo stato HTTP 200 OK. Il client memorizza nella cache la risposta insieme alla data. In una richiesta successiva, il client invia l’header If-Modified-Since con la data salvata. Il server confronta questa data con l’ora corrente di modifica della risorsa. Se la risorsa non è cambiata — restituisce 304 Not Modified con corpo vuoto. Se è cambiata — 200 OK con nuovi dati e un nuovo Last-Modified.

http
// Prima richiesta — il server restituisce la risorsa con una data
HTTP/1.1 200 OK
Content-Type: application/json
Last-Modified: Wed, 02 Jul 2025 14:30:00 GMT

[{"id": 1, "name": "Alice"}]

// Richiesta ripetuta — il client invia la data salvata
GET /api/users HTTP/1.1
Host: example.com
If-Modified-Since: Wed, 02 Jul 2025 14:30:00 GMT

// Risposta — i dati non sono cambiati
HTTP/1.1 304 Not Modified

Per le applicazioni mobili, Last-Modified è particolarmente utile per la sincronizzazione dei dati. L’app salva la data dell’ultimo aggiornamento riuscito e la invia al server in If-Modified-Since. Se ci sono più dati o sono cambiati — il server restituisce il set completo. Altrimenti — 304, e l’app usa la copia locale. OkHttp e URLSession supportano questo meccanismo automaticamente tramite sistemi di cache integrati.

Come il server determina la data

Per i file statici, Nginx e Apache prendono la data dagli attributi del filesystem — mtime (ora di modifica). Per i contenuti dinamici, il codice del server deve impostare esplicitamente Last-Modified in base alla logica di business: il campo updated_at del database, la data dell’ultimo commit Git, il timestamp dell’artefatto di build. Se Last-Modified non viene impostato esplicitamente, il server potrebbe non inviare affatto l’header e il client non sarà in grado di effettuare richieste condizionali per data.

Last-Modified vs ETag

Last-Modified ed ETag svolgono un compito simile — permettere al client di verificare l’attualità della cache — ma hanno differenze sostanziali. Last-Modified usa un timestamp, ETag usa un identificatore unico di versione. Ogni approccio ha i suoi scenari in cui è più efficace e la specifica HTTP raccomanda di usare entrambi gli header insieme.

CriterioLast-ModifiedETag
EssenzaData dell’ultima modificaIdentificatore unico di versione
PrecisioneAl secondoAl bit (hash)
Complessità d’implementazioneBassa — automatica dal filesystemMedia — richiede calcolo dell’hash
Server in clusterProblema: mtime può variare tra nodiStabile con dati identici tra nodi
Supporto intervalliNon influisce sulle richieste RangeRichiede ETag forte per gli intervalli
RaccomandazionePer file statici e API sempliciPer API dove serve una verifica precisa

Il principale vantaggio di Last-Modified è la semplicità. Il server non deve calcolare un hash del contenuto, risparmiando risorse CPU per ogni richiesta. Per progetti ad alto traffico che servono file statici o dati con timestamp chiari, Last-Modified rimane la scelta ottimale. ETag, d’altro canto, offre una precisione assoluta — cambiare una singola lettera in una risposta JSON modificherà l’ETag, ma potrebbe non cambiare la data (se il file è stato sovrascritto con la stessa versione).

Uso congiunto

La specifica raccomanda di restituire entrambi gli header contemporaneamente. Il server include sia Last-Modified che ETag nella risposta 200 OK. Il client invia entrambi gli header condizionali — If-Modified-Since e If-None-Match. Il server controlla prima ETag (ha priorità), poi Last-Modified. Se almeno uno segnala un cambiamento — viene restituita la risposta completa. Ciò offre la massima flessibilità: ETag garantisce precisione, Last-Modified fornisce un controllo di fallback per i client che non supportano ETag.

Configurazione di Last-Modified sul server

La configurazione di Last-Modified dipende dal tipo di server. Per Nginx e Apache, Last-Modified viene impostato automaticamente per i file statici in base a mtime. Per le applicazioni dinamiche, l’header deve essere impostato nel codice del server. Vediamo la configurazione sulle piattaforme più popolari.

javascript
// Express.js — impostazione di Last-Modified
app.get("/api/users", async (req, res) => {
    const updatedAt = await getLastUpdate()
    const ifModifiedSince = req.get("If-Modified-Since")

    // Verifica di 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)
})

Nell’esempio Express.js, il server ottiene la data dell’ultimo aggiornamento dei dati dal database, controlla If-Modified-Since del client e, se la cache è ancora fresca, restituisce 304. Se i dati sono cambiati — imposta un nuovo Last-Modified e restituisce la risposta completa. toUTCString() converte la data nel formato HTTP richiesto. In produzione, è bene memorizzare updatedAt nella cache Redis per evitare una query al database a ogni richiesta.

Nginx: configurazione di Last-Modified

Nginx imposta automaticamente Last-Modified per i file statici in base all’ora dell’ultima modifica del file. È possibile disabilitare o modificare questo comportamento tramite la direttiva etag (disabilitazione di ETag) o attraverso il modulo ngx_http_headers_module. Per le richieste proxy al backend, Last-Modified viene passato dalla risposta upstream senza modifiche. Importante: se il backend non restituisce Last-Modified, Nginx non lo aggiungerà automaticamente per le risposte dinamiche.

Limitazioni e insidie

Last-Modified ha diverse limitazioni note. La principale è la precisione al secondo. Se una risorsa cambia due volte entro un secondo, il client potrebbe perdere la nuova versione. Nella pratica è uno scenario raro, ma per aggiornamenti ad alta frequenza (feed di ticker, chat) si raccomanda ETag. La seconda limitazione è il problema del clustering: su server diversi, un file può avere mtime diverso a causa di copie o deployment, rendendo Last-Modified incoerente.

La terza limitazione — la gestione di If-Modified-Since con precisione al secondo può generare richieste non necessarie quando si interroga frequentemente il server. Se il client invia If-Modified-Since ogni 500 ms, il server restituisce 200 OK ogni volta perché la data non è cambiata, ma la risorsa è già stata aggiornata. La soluzione è usare una combinazione con ETag: ETag rileverà il cambiamento entro un secondo, mentre Last-Modified rimane come fallback.

Il quarto problema — Last-Modified non distingue tra versioni diverse della stessa risorsa con la stessa data. Se un file viene ripristinato da un backup e il suo mtime corrisponde all’originale, il client non noterà che il contenuto è cambiato. ETag risolve questo problema: l’hash del contenuto cambierà sicuramente con qualsiasi modifica dei dati, indipendentemente dal timestamp. Per i dati critici, utilizzare sempre entrambi gli header.

  • Precisione al secondo — non rileva cambiamenti entro un secondo; usare ETag per aggiornamenti ad alta frequenza
  • Clustering — mtime può variare tra server; sincronizzare via NTP o usare ETag
  • Condizione di competizione — se la risorsa cambia dopo l’invio di If-Modified-Since ma prima del controllo del server
  • Interpretazione errata del proxy — alcuni proxy possono modificare Last-Modified durante il caching; HTTPS risolve

Domande frequenti

Quale formato di data viene utilizzato in Last-Modified?

Solo GMT (Greenwich Mean Time) in formato RFC 1123: giorno della settimana, giorno, mese, anno, ore:minuti:secondi. Esempio: Wed, 02 Jul 2025 14:30:00 GMT. Il fuso orario è sempre GMT, altri formati non sono consentiti.

Last-Modified può essere nel futuro?

Tecnicamente sì, ma viola RFC 7232. Se il server restituisce una data futura, i client non aggiorneranno la risorsa fino al suo arrivo. Tale configurazione è considerata un errore — la data deve essere nel passato o nel presente.

Last-Modified funziona con le richieste POST?

No, le richieste condizionali If-Modified-Since funzionano solo con GET e HEAD. Le richieste POST non vengono memorizzate nella cache e non utilizzano la validazione per data. Per i controlli di aggiornamento in POST, utilizzare ETag o meccanismi personalizzati.

Come interagisce Last-Modified con Cache-Control?

Cache-Control definisce la politica di caching (tempo massimo di memorizzazione, chi può memorizzare), mentre Last-Modified è un meccanismo di validazione per la cache scaduta. Dopo la scadenza del max-age, il client invia If-Modified-Since per verificare l’attualità.

Cosa fare se Last-Modified non cambia quando i dati vengono aggiornati?

Verificare che il server stia effettivamente impostando l’header dalla fonte corretta — database, filesystem o API. Per le risposte dinamiche, assicurarsi di chiamare esplicitamente res.setHeader(“Last-Modified”, ...) nel codice del gestore.

Riepilogo

  • Last-Modified — header HTTP con la data dell’ultima modifica della risorsa per richieste condizionali 304
  • Implementazione semplice — funziona automaticamente per i file statici (mtime) e richiede codice minimo per le API
  • Precisione al secondo — il limite principale; per cambiamenti ad alta frequenza utilizzare ETag
  • ETag è più preciso, Last-Modified è più semplice — combinazione ottimale: entrambi gli header insieme
  • Formato data HTTP — solo GMT, RFC 1123, lunghezza fissa di 29 caratteri
  • Clustering — richiede sincronizzazione dell’ora (NTP) o l’uso di ETag come meccanismo principale
  • Raccomandazione — aggiungere sempre Last-Modified per le API e abilitarlo per i file statici tramite Nginx/Apache

Svilupperemo un'applicazione mobile chiavi in mano

IT Sectr crea applicazioni iOS e Android per startup e aziende dal 2017. Ti consulteremo e ti proporremo la soluzione migliore.

Discuti il progetto

Leggi anche