Conditional GET (warunkowe żądanie GET) — mechanizm HTTP pozwalający klientowi sprawdzić aktualność buforowanego zasobu przed pełnym załadowaniem. Klient wysyła żądanie GET z nagłówkami If-None-Match (zawiera ETag) lub If-Modified-Since (zawiera datę), a serwer zwraca 304 Not Modified bez treści odpowiedzi, jeśli zasób się nie zmienił. Według MDN Web Docs, 2025, żądania warunkowe zmniejszają ruch sieciowy serwerów i klientów. 304 Not Modified — kluczowy status HTTP dla efektywnej synchronizacji aplikacji mobilnych.
Najważniejsze
Conditional GET — to żądanie GET zawierające jeden lub więcej nagłówków warunkowych, na podstawie których serwer decyduje, czy zwrócić pełną odpowiedź, czy tylko status 304 Not Modified. Głównym celem jest uniknięcie przesyłania treści odpowiedzi, jeśli zasób nie zmienił się od ostatniego żądania. To fundamentalny mechanizm buforowania HTTP, zdefiniowany w specyfikacji RFC 7232.
Dla aplikacji mobilnych Conditional GET to jeden z najskuteczniejszych sposobów optymalizacji ruchu sieciowego. Typowy scenariusz: przy otwieraniu aplikacji klient wysyła serię warunkowych żądań GET w celu załadowania kanału, profilu i ustawień. Jeśli dane się nie zmieniły, aplikacja otrzymuje 304 i korzysta z lokalnej kopii. Zajmuje to milisekundy zamiast sekund i nie zużywa transferu mobilnego.
Według Google Web Fundamentals (2025), wdrożenie warunkowych żądań GET w aplikacji mobilnej skraca średni czas ładowania o 40–60% dla ponownych odwiedzin i zmniejsza zużycie transferu o 70–90% dla stron z rzadkimi aktualizacjami. Efekt jest szczególnie widoczny przy wolnych połączeniach (3G, Edge), gdzie liczy się każdy bajt.
Proces składa się z trzech kroków. Pierwszy — klient wysyła zwykłe żądanie GET, serwer zwraca zasób wraz z nagłówkami buforowania (ETag, Last-Modified). Drugi — klient zapisuje zasób i jego walidatory lokalnie. Trzeci — przy ponownym żądaniu klient wysyła GET z If-None-Match (dla ETag) i/lub If-Modified-Since (dla Last-Modified). Serwer sprawdza walidatory i odpowiada 304, jeśli zasób się nie zmienił, albo 200 z nowymi danymi.
Serwer używa priorytetu ETag nad Last-Modified przy obecności obu nagłówków. Wynika to z faktu, że ETag zapewnia dokładniejszą walidację — skrót zawartości zmienia się przy każdej modyfikacji, podczas gdy Last-Modified ma rozdzielczość jednej sekundy. Jeśli ETag jest zgodny, serwer natychmiast zwraca 304, nie sprawdzając Last-Modified.
Przykład pełnego cyklu Conditional GET w sekwencji żądań:
// Krok 1: Pierwsze żądanie — pobierz dane i ETag
GET /api/profile
Response: 200 OK
ETag: "33a64df551425fcc55e"
Body: { "name": "Alice" }
// Krok 2: Powtórz żądanie — z If-None-Match
GET /api/profile
If-None-Match: "33a64df551425fcc55e"
Response: 304 Not Modified
// Treść odpowiedzi jest nieobecna — użyj lokalnej kopii
W drugim żądaniu serwer porównuje ETag z If-None-Match z bieżącym skrótem zasobu. Przy zgodności zwracane jest 304 bez treści — klient kontynuuje korzystanie z buforowanych danych. To jest istota Conditional GET: minimum ruchu przy maksymalnej aktualności danych.
Zwykłe żądanie GET zawsze zwraca pełną odpowiedź 200 OK z treścią. Nawet jeśli zasób się nie zmienił, serwer przesyła wszystkie dane od nowa. Jest to akceptowalne dla małych zasobów lub przy rzadkich żądaniach, ale dla aplikacji mobilnych z setkami żądań przy każdym uruchomieniu takie podejście prowadzi do nadmiernego zużycia transferu i baterii.
Conditional GET dodaje narzut w postaci nagłówków (zazwyczaj 50–200 bajtów na żądanie), ale oszczędza kilobajty i megabajty przy odpowiedzi 304. Im większy zasób, tym bardziej opłaca się żądanie warunkowe. Dla obrazów, list danych i dokumentów JSON o rozmiarze od 10 KB Conditional GET zwraca się już przy pierwszym ponownym żądaniu.
Porównanie obu podejść:
| Parametr | Zwykłe GET | Conditional GET |
|---|---|---|
| Ruch (brak zmian) | Pełna odpowiedź | Tylko nagłówki (~200 bajtów) |
| Opóźnienie | Pełne ładowanie | Milisekundy (304) |
| Obciążenie serwera | Generacja + przesłanie | Tylko sprawdzenie ETag |
| Złożoność implementacji | Minimalna | Wymaga przechowywania ETag |
| Efektywność dla dużych danych | Niska | Wysoka |
Rozważmy pełną implementację Conditional GET w Kotlin z użyciem OkHttp i Room do przechowywania ETag. Aplikacja listy zadań ładuje zadania z serwera i używa warunkowych żądań w celu minimalizacji ruchu. ETag są przechowywane w lokalnej bazie danych, aby zachować je między sesjami.
Repozytorium z Conditional GET w Kotlin:
class TaskRepository(
private val api: TaskApi,
private val etagDao: EtagDao
) {
suspend fun getTasks(): List<Task> {
val savedEtag = etagDao.getEtag("tasks")
val response = api.fetchTasks(
ifNoneMatch = savedEtag
)
return when (response.code()) {
304 -> taskDao.getAll() // z lokalnego bufora
200 -> {
response.header("ETag")?.let {
etagDao.saveEtag("tasks", it)
}
val tasks = response.body() ?: emptyList()
taskDao.replaceAll(tasks)
tasks
}
else -> throw Exception(
"Sync failed: ${response.code()}")
}
}
}
TaskRepository sprawdza kod odpowiedzi: 304 oznacza brak zmian, a dane są zwracane z lokalnego bufora Room. Przy 200 nowy ETag jest zapisywany, a zadania aktualizowane w lokalnej bazie. Ten wzorzec to standard dla aplikacji mobilnych synchronizujących się przez REST API.
Conditional GET jest szeroko stosowany w aplikacjach mobilnych do optymalizacji synchronizacji danych. Główne scenariusze: ładowanie kanału wiadomości (Twitter, Instagram okresowo odpytywa API z If-None-Match), aktualizacja profilu użytkownika, ładowanie listy powiadomień i synchronizacja zadań. W każdym przypadku aplikacja może sprawdzać aktualność danych bez ponownego ich pobierania.
Dla aplikacji offline-first Conditional GET służy jako pierwszy etap synchronizacji. Aplikacja najpierw wysyła warunkowe żądania GET dla wszystkich zasobów, które zostały zmodyfikowane lokalnie od ostatniej synchronizacji. Zasoby z 304 nie wymagają pobierania. Następnie aplikacja wysyła PUT/POST dla lokalnych zmian. Takie dwufazowe podejście zapewnia minimalne zużycie transferu.
W połączeniu z Conflict Resolution Conditional GET pozwala skutecznie wykrywać konflikty. Jeśli klient otrzymał 200 z nowymi danymi (zasób się zmienił), ale klient ma niewysłane lokalne zmiany — rejestrowany jest konflikt. Klient może zastosować LWW (zmiany lokalne są tracone) lub uruchomić Merge Strategy w celu połączenia lokalnych i zdalnych zmian. Według Meta Engineering Blog (2025), wdrożenie Conditional GET w Messenger zmniejszyło średnie zużycie transferu przy synchronizacji o 73%.
Często zadawane pytania
Conditional GET — żądanie HTTP GET z nagłówkami warunkowymi (If-None-Match, If-Modified-Since). Serwer zwraca 304 Not Modified, jeśli zasób się nie zmienił, lub 200 z nowymi danymi. To mechanizm efektywnego buforowania.
Zwykłe GET zawsze zwraca pełną odpowiedź z treścią. Conditional GET dodaje nagłówki sprawdzania wersji (ETag, data). Jeśli dane się nie zmieniły, serwer odpowiada 304 bez treści, oszczędzając transfer i czas ładowania.
Do efektywnego buforowania zapisuj ETag i Last-Modified z każdej odpowiedzi serwera w lokalnej bazie danych. Przy następnym żądaniu wysyłaj je w nagłówkach If-None-Match i If-Modified-Since. Przy 304 używaj danych z lokalnego bufora.
Przy odpowiedzi 304 serwer nie przesyła treści odpowiedzi — tylko nagłówki (~200 bajtów). Dla zasobu o rozmiarze 50 KB oznacza to oszczędność 99,6% transferu. Dla aplikacji synchronizującej się 50 razy dziennie oszczędność sięga dziesiątek megabajtów miesięcznie.
Tak, to standardowe podejście do synchronizacji delta. Klient sprawdza aktualność każdego zasobu przez Conditional GET, pobiera tylko zmienione i wysyła lokalne zmiany. Takie podejście jest stosowane w Twitter, Instagram, Telegram i większości nowoczesnych API.
Podsumowanie
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.
Przeczytaj również