Last-Modified — istota, mechanizm i konfiguracja nagłówka daty modyfikacji

Autor: IT Sectr Opublikowano: 2026-03-09 Czas czytania: 9 min

Last-Modified — nagłówek odpowiedzi HTTP, który wskazuje datę i czas ostatniej modyfikacji zasobu na serwerze, umożliwiając klientowi wykonywanie żądań warunkowych przez If-Modified-Since. Jeśli zasób nie zmienił się od podanej daty, serwer zwraca 304 Not Modified bez przesyłania treści odpowiedzi, co znacząco oszczędza przepustowość. Według RFC 7232 (IETF, 2014), żądania warunkowe z Last-Modified skracają czas ładowania stron o 30–60% przy ponownych odwiedzinach. Nagłówek jest automatycznie obsługiwany przez większość serwerów HTTP i proxy.

Najważniejsze

  • Last-Modified — nagłówek HTTP z datą ostatniej modyfikacji zasobu dla żądań warunkowych If-Modified-Since
  • 304 Not Modified — odpowiedź serwera, jeśli zasób się nie zmienił; klient używa swojej buforowanej kopii
  • Dokładność do sekundy — ograniczenie nagłówka: zmiany w ciągu jednej sekundy mogą pozostać niezauważone
  • Współpraca z ETag — serwer zwraca oba nagłówki, klient wysyła oba żądania warunkowe
  • Automatyczna generacja — Nginx i Apache ustawiają Last-Modified dla statyki z systemu plików

Co to jest Last-Modified?

Last-Modified — to nagłówek HTTP należący do grupy nagłówków żądań warunkowych (conditional requests). Serwer dodaje go do odpowiedzi na GET lub HEAD, wskazując datę i czas ostatniej modyfikacji żądanego zasobu w formacie HTTP-date: Last-Modified: Wed, 02 Jul 2025 14:30:00 GMT. Klient (przeglądarka, aplikacja mobilna, proxy) zapisuje tę datę wraz z buforowanym zasobem. Przy ponownym żądaniu klient wysyła nagłówek If-Modified-Since z tą samą datą, a serwer porównuje ją z bieżącym czasem modyfikacji zasobu.

Protokół żądań warunkowych z Last-Modified jest zdefiniowany w RFC 7232 i obsługiwany przez wszystkie nowoczesne serwery HTTP. Format daty jest ściśle określony — tylko GMT (Greenwich Mean Time) bez wskazywania strefy czasowej. Serwer może zwracać datę w trzech możliwych formatach: RFC 1123 (standardowy), RFC 850 (przestarzały) lub ANSI C asctime. W praktyce prawie wszystkie serwery używają formatu RFC 1123 o stałej długości 29 znaków.

Last-Modified należy do kategorii mechanizmów walidacyjnych buforowania: nie mówi klientowi, czy można buforować odpowiedź, ale daje narzędzie do sprawdzania aktualności już zbuforowanego zasobu. Polityka buforowania jest określana osobno przez nagłówek Cache-Control. Według badań Akamai (2025), prawidłowa konfiguracja Last-Modified wraz z Cache-Control zmniejsza obciążenie serwerów origin aż do 70% dla treści statycznych.

Kiedy pojawił się Last-Modified

Nagłówek Last-Modified został zdefiniowany już w HTTP/1.0 (RFC 1945, 1996) i był jednym z pierwszych mechanizmów zarządzania buforowaniem w sieci. Przed pojawieniem się ETag w HTTP/1.1 był to jedyny sposób wykonywania żądań warunkowych. Pomimo wieku nagłówek pozostaje aktualny dzięki swojej prostocie — serwer nie musi obliczać skrótu treści, wystarczy odczytać timestamp pliku z systemu plików lub pole updated_at z bazy danych.

Jak działa Last-Modified?

Pełny cykl obejmuje trzy etapy. Przy pierwszym żądaniu serwer zwraca zasób z nagłówkiem Last-Modified i statusem HTTP 200 OK. Klient buforuje odpowiedź wraz z datą. Przy ponownym żądaniu klient wysyła nagłówek If-Modified-Since z zapisaną datą. Serwer porównuje tę datę z bieżącym czasem modyfikacji zasobu. Jeśli zasób nie został zmodyfikowany — zwracane jest 304 Not Modified z pustą treścią. Jeśli został zmodyfikowany — 200 OK z nowymi danymi i nowym Last-Modified.

http
// Pierwsze żądanie — serwer zwraca zasób z datą
HTTP/1.1 200 OK
Content-Type: application/json
Last-Modified: Wed, 02 Jul 2025 14:30:00 GMT

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

// Powtórne żądanie — klient wysyła zapisaną datę
GET /api/users HTTP/1.1
Host: example.com
If-Modified-Since: Wed, 02 Jul 2025 14:30:00 GMT

// Odpowiedź — dane nie uległy zmianie
HTTP/1.1 304 Not Modified

Dla aplikacji mobilnych Last-Modified jest szczególnie przydatny przy synchronizacji danych. Aplikacja zapisuje datę ostatniej udanej aktualizacji i wysyła ją serwerowi w If-Modified-Since. Jeśli danych jest więcej lub uległy zmianie — serwer zwraca pełny zestaw. Jeśli nie — 304, a aplikacja używa lokalnej kopii. OkHttp i URLSession obsługują ten mechanizm automatycznie przez wbudowane systemy buforowania.

Jak serwer określa datę

Dla plików statycznych Nginx i Apache pobierają datę z atrybutów systemu plików — mtime (czas modyfikacji). Dla treści dynamicznych kod serwera musi jawnie ustawiać Last-Modified na podstawie logiki biznesowej: pole updated_at z bazy danych, data ostatniego commita w Git, timestamp budowy artefaktu. Jeśli Last-Modified nie jest jawnie ustawiony, serwer może w ogóle nie zwracać nagłówka, a klient nie będzie mógł wykonywać żądań warunkowych według daty.

Last-Modified vs ETag

Last-Modified i ETag pełnią podobne zadanie — umożliwiają klientowi sprawdzenie aktualności bufora — ale mają zasadnicze różnice. Last-Modified używa znacznika czasu, ETag — unikalnego identyfikatora wersji. Każde podejście ma swoje scenariusze, w których jest skuteczniejsze, a zalecenie specyfikacji HTTP to używanie obu nagłówków razem.

KryteriumLast-ModifiedETag
IstotaData ostatniej modyfikacjiUnikalny identyfikator wersji
DokładnośćDo sekundyDo bitu (skrót)
Złożoność implementacjiNiska — automatycznie z systemu plikówŚrednia — wymaga obliczania skrótu
Serwery klastroweProblem: mtime może się różnić na węzłachStabilny przy identycznych danych na węzłach
Obsługa zakresówNie wpływa na Range requestsWymaga silnego ETag dla zakresów
ZalecenieDla statyki i prostych APIDla API gdzie ważna jest dokładna weryfikacja

Główną zaletą Last-Modified jest prostota. Serwer nie musi obliczać skrótu zawartości, co oszczędza zasoby CPU przy każdym żądaniu. Dla projektów o wysokim obciążeniu, które dostarczają pliki statyczne lub dane z wyraźnymi znacznikami czasu, Last-Modified pozostaje optymalnym wyborem. ETag natomiast daje absolutną dokładność — zmiana jednej litery w odpowiedzi JSON zmieni ETag, ale może nie zmienić daty (jeśli plik został nadpisany tą samą wersją).

Wspólne używanie

Specyfikacja zaleca zwracanie obu nagłówków jednocześnie. Serwer dołącza zarówno Last-Modified, jak i ETag w odpowiedzi 200 OK. Klient wysyła oba nagłówki warunkowe — If-Modified-Since i If-None-Match. Serwer sprawdza najpierw ETag (ma priorytet), potem Last-Modified. Jeśli przynajmniej jeden sygnalizuje zmianę — zwracana jest pełna odpowiedź. Daje to maksymalną elastyczność: ETag zapewnia dokładność, Last-Modified — zapasowe sprawdzenie dla klientów nieobsługujących ETag.

Konfiguracja Last-Modified na serwerze

Konfiguracja Last-Modified zależy od typu serwera. Dla Nginx i Apache plikom statycznym Last-Modified jest ustawiany automatycznie na podstawie mtime. Dla aplikacji dynamicznych nagłówek trzeba ustawić w kodzie serwera. Przyjrzyjmy się konfiguracji na popularnych platformach.

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

    // Sprawdzanie 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)
})

W przykładzie na Express.js serwer pobiera datę ostatniej aktualizacji danych z bazy, sprawdza If-Modified-Since od klienta i przy aktualności bufora zwraca 304. Jeśli dane się zmieniły — ustawia nowy Last-Modified i zwraca pełną odpowiedź. toUTCString() przekształca datę na wymagany format HTTP. W środowisku produkcyjnym warto dodać buforowanie updatedAt w Redis, aby nie wykonywać zapytania do bazy przy każdym dostępie.

Nginx: konfiguracja Last-Modified

Nginx automatycznie ustawia Last-Modified dla plików statycznych na podstawie czasu ostatniej modyfikacji pliku. Wyłączyć lub zmienić zachowanie można dyrektywą etag (wyłączenie ETag) lub przez moduł ngx_http_headers_module. Dla żądań proxy do backendu Last-Modified jest przekazywany z odpowiedzi upstream bez zmian. Ważne: jeśli backend nie zwraca Last-Modified, Nginx nie doda go automatycznie dla odpowiedzi dynamicznych.

Ograniczenia i pułapki

Last-Modified ma kilka znanych ograniczeń. Głównym jest dokładność do sekundy. Jeśli zasób zmienił się dwukrotnie w ciągu jednej sekundy, klient może przegapić nową wersję. W praktyce jest to rzadki scenariusz, ale w przypadku częstych aktualizacji (kanały notowań, czaty) zaleca się ETag. Drugie ograniczenie to problem klasteryzacji: na różnych serwerach plik może mieć różny mtime z powodu kopiowania lub wdrożenia, przez co Last-Modified będzie niespójny.

Trzecie ograniczenie — obsługa If-Modified-Since z dokładnością do sekundy może prowadzić do zbędnych żądań przy częstym odpytywaniu serwera. Jeśli klient wysyła If-Modified-Since co 500 ms, serwer za każdym razem zwraca 200 OK, ponieważ data się nie zmieniła, ale zasób faktycznie został już zaktualizowany. Rozwiązaniem jest użycie kombinacji z ETag: ETag wykryje zmianę w ciągu sekundy, a Last-Modified pozostanie jako rezerwa.

Czwarty problem — Last-Modified nie rozróżnia różnych wersji tego samego zasobu z tą samą datą. Jeśli plik został przywrócony z kopii zapasowej i jego mtime zgadza się z oryginalnym, klient nie zauważy, że treść się zmieniła. ETag rozwiązuje ten problem: skrót treści gwarantowanie zmieni się przy każdej zmianie danych, niezależnie od znacznika czasu. W przypadku danych krytycznych zawsze używaj obu nagłówków.

  • Dokładność do sekundy — nie wykrywa zmian w ciągu jednej sekundy; użyj ETag dla częstych aktualizacji
  • Klasteryzacja — mtime może się różnić na różnych serwerach; synchronizuj przez NTP lub użyj ETag
  • Race condition — jeśli zasób zmienił się po wysłaniu If-Modified-Since, ale przed sprawdzeniem na serwerze
  • Błędna interpretacja przez proxy — niektóre proxy mogą zmienić Last-Modified podczas buforowania; HTTPS rozwiązuje ten problem

Często zadawane pytania

Jaki format daty jest używany w Last-Modified?

Tylko GMT (Greenwich Mean Time) w formacie RFC 1123: dzień tygodnia, data, miesiąc, rok, godziny:minuty:sekundy. Przykład: Wed, 02 Jul 2025 14:30:00 GMT. Strefa czasowa to zawsze GMT, inne formaty nie są dozwolone.

Czy Last-Modified może być w przyszłości?

Technicznie może, ale narusza to RFC 7232. Jeśli serwer zwraca datę w przyszłości, klienci nie będą aktualizować zasobu do momentu nadejścia tej daty. Taka konfiguracja jest uważana za błąd — data powinna być w przeszłości lub teraźniejszości.

Czy Last-Modified działa z żądaniami POST?

Nie, żądania warunkowe If-Modified-Since działają tylko z GET i HEAD. Żądania POST nie są buforowane i nie używają walidacji według daty. Do sprawdzania aktualności danych dla POST używaj ETag lub własnych mechanizmów.

Jak Last-Modified współdziała z Cache-Control?

Cache-Control określa politykę buforowania (maksymalny czas przechowywania, kto może buforować), a Last-Modified to mechanizm walidacji nieaktualnego bufora. Po wygaśnięciu max-age klient wysyła If-Modified-Since w celu sprawdzenia aktualności.

Co zrobić, jeśli Last-Modified nie zmienia się przy aktualizacji danych?

Sprawdź, czy serwer rzeczywiście ustawia nagłówek z aktualnego źródła — bazy danych, systemu plików lub API. Dla odpowiedzi dynamicznych upewnij się, że jawnie wywołujesz res.setHeader(„Last-Modified”, ...) w kodzie procedury obsługi.

Podsumowanie

  • Last-Modified — nagłówek HTTP z datą ostatniej modyfikacji zasobu dla żądań warunkowych 304
  • Prostota implementacji — działa automatycznie dla statyki (mtime pliku) i wymaga minimalnego kodu dla API
  • Dokładność do sekundy — główne ograniczenie; dla częstych zmian używaj ETag
  • ETag dokładniejszy, Last-Modified prostszy — optymalna kombinacja: oba nagłówki razem
  • Format daty HTTP — tylko GMT, RFC 1123, stała długość 29 znaków
  • Klasteryzacja — wymaga synchronizacji czasu (NTP) lub użycia ETag jako głównego mechanizmu
  • Zalecenie — zawsze dodawaj Last-Modified dla API i włącz dla statyki przez Nginx/Apache

Opracujemy aplikację mobilną pod klucz

IT Sectr tworzy aplikacje na iOS i Androida dla startupów i firm od 2017 roku. Doradzimy Ci i zaproponujemy najlepsze rozwiązanie.

Omów projekt

Przeczytaj również