Jak konfigurować HTTP caching dla API
Ten artykuł opisuje praktyczne podejście do konfigurowania HTTP caching dla API — od podstawowych zasad po zaawansowane techniki stosowane z CDN i reverse proxy. Przedstawione wskazówki wyjaśniają, kiedy cache pomaga przyspieszyć odpowiedzi, jak poprawnie ustawić nagłówki i jakie pułapki unikać przy uwierzytelnianiu, dynamicznych treściach i invalidacji. Celem jest dostarczenie konkretnych reguł, które można zastosować w typowych scenariuszach projektowania API.
Podstawy i zasady działania cache w HTTP
Cache w kontekście HTTP pozwala przechowywać kopie odpowiedzi bliżej klienta (przeglądarka, CDN) lub pośredników (reverse proxy), co redukuje opóźnienia i obciążenie serwera źródłowego. Najważniejsza zasada to rozdzielenie odpowiedzi na te, które są bezpiecznie ponownie używalne, oraz na te, które wymagają każdorazowego odświeżenia. W praktyce to oznacza, że metody GET i HEAD są głównymi kandydatami do cache’owania, podczas gdy POST, PUT i DELETE zwykle nie są cache’owane bez dodatkowych mechanizmów.
Podstawowe pojęcia, które warto znać:
- Cache-Control — główny nagłówek kontrolujący politykę pamięci podręcznej.
- ETag — walidator zasobu wykorzystywany do warunkowych zapytań.
- Last-Modified — alternatywny walidator oparty na dacie modyfikacji.
- 304 Not Modified — odpowiedź wskazująca, że zawartość nie uległa zmianie i można użyć wersji w cache.
Konfiguracja nagłówków Cache-Control i inne kluczowe dyrektywy
Najważniejszym mechanizmem jest nagłówek Cache-Control. Powinien być ustawiany świadomie, bo determinuje zachowanie zarówno przeglądarek, jak i pośredników. Typowe dyrektywy:
- max-age=
— ile czasu odpowiedź jest świeża bez dodatkowej walidacji. - s-maxage — analogiczne do max-age, ale dotyczy wyłącznie współdzielonych cache (CDN, proxy). Przydatne, gdy chcemy różnych TTL dla klienta i CDN.
- public — odpowiedź może być buforowana przez dowolny cache (w tym CDN).
- private — odpowiedź powinna być trzymana tylko w cache użytkownika (np. przeglądarka), nie w cache współdzielonym.
- no-store — nie przechowywać odpowiedzi na dysku; używane dla danych wrażliwych.
- no-cache — cache może przechować odpowiedź, ale przed ponownym użyciem musi zweryfikować u źródła (warunkowe zapytanie).
- must-revalidate — po wygaśnięciu odpowiedzi cache musi odnowić ją u źródła przed użyciem.
- stale-while-revalidate i stale-if-error — rozszerzenia pozwalające zwracać przeterminowaną wersję podczas rewalidacji lub gdy źródło jest niedostępne.
Przykładowe polityki
Dobrym punktem wyjścia dla API, które zwraca rzadko zmieniające się zasoby, jest ustawienie:
- Cache-Control: public, max-age=3600, s-maxage=3600
Dla danych spersonalizowanych:
- Cache-Control: private, max-age=60
Dla bardzo wrażliwych informacji:
- Cache-Control: no-store
Walidatory: ETag, Last-Modified i zapytania warunkowe
Walidatory pozwalają uniknąć pobierania pełnej treści, gdy zasób się nie zmienił. Mechanizmy te zmniejszają transfer danych i obciążenie serwera.
- ETag — wartość unikalnie identyfikująca wersję zasobu. Serwer generuje ją (np. hash zawartości) i klient przekazuje w If-None-Match. Jeśli ETagy pasują, serwer zwraca 304.
- Last-Modified — służy do porównania z If-Modified-Since. Jest prostszy, ale mniej precyzyjny niż ETag (problemy z dokładnością czasów).
W praktyce ETagy są bardziej wiarygodne dla dynamicznych treści. Pamiętaj o rozróżnieniu walidatorów silnych i słabych (weak ETag — prefiks W/), co ma znaczenie, gdy porównanie powinno uwzględniać drobne różnice typu formatowania.
Cache a autoryzacja i prywatne dane
Domyślnie odpowiedzi z nagłówkiem Authorization nie powinny być buforowane przez współdzielone cache, chyba że jawnie to pozwolimy (np. Cache-Control: public, s-maxage=…). Najbezpieczniejsze praktyki:
- Nie cache’uj odpowiedzi zawierających dane wrażliwe bez silnej kontroli dostępu.
- Używaj private dla treści specyficznych dla użytkownika.
- Jeśli twoje API wymaga tokenów, rozważ mechanizm cache’owania po stronie CDN tylko dla wybranych endpointów i z krótkim TTL.
Strategie invalidacji i modelowania klucza cache
Invalidacja cache to często najtrudniejszy fragment projektowania. Dostępne podejścia:
- Ustalanie krótkiego TTL (prostota kosztem częściej odświeżeń).
- Wysyłanie zdarzeń invalidacji do CDN/reverse proxy (purge API). Skuteczne, gdy potrafisz wskazać precyzyjnie URL-e do usunięcia.
- Wersjonowanie zasobów przez URL (np. /v1/resources/123?v=20260718) — przydatne, gdy chcesz zachować stary cache przy wprowadzaniu zmian w schemacie.
- Cache key — decyduje, które atrybuty żądania wpływają na unikalność wpisu (metoda, host, ścieżka, query string, nagłówki). Precyzyjne modelowanie klucza pozwala uniknąć kolizji i nadmiarowego cache’owania.
Praktyczne reguły invalidacji
W większości systemów:
- Stosuj purge dla konkretnych URL zamiast globalnego kasowania.
- Utrzymuj mapę zależności: które zasoby wpływają na inne (np. zmiana zasobu A wymusza odświeżenie listy B).
- W razie wątpliwości preferuj krótsze TTL przy krytycznych danych.
Wykorzystanie CDN i reverse proxy
CDN i reverse proxy (np. Varnish, Fastly, AWS CloudFront) mogą znacząco poprawić wydajność. Najważniejsze kwestie:
- Rozróżnij TTL dla s-maxage (CDN) i max-age (przeglądarka). Pozwala to serwerowi przyznać inną żywotność treści na CDN niż u klienta końcowego.
- Dostosuj Vary jeśli odpowiedź zależy od nagłówków (np. Accept-Language). Użycie Vary rozszerzy liczbę wpisów w cache, więc stosuj świadomie.
- Używaj mechanizmów purge i surrogate-control dostępnych w CDN do precyzyjnej invalidacji.
Obsługa parametrów zapytania, cookie i nagłówków Vary
Zasady:
- Query string — decyduje o kluczu cache. Niektóre CDNy traktują różne kombinacje parametrów jako ten sam wpis, jeśli nie skonfigurujesz inaczej. Znormalizuj kolejność parametrów i ignoruj nieistotne parametry.
- Cookies — mogą unieważniać cache. Jeśli cookies nie zmieniają treści, usuń je z żądania kierowanego do cache lub uwzględnij tylko konkretne cookie w kluczu.
- Vary — używaj tylko gdy odpowiedź zmienia się w zależności od konkretnego nagłówka (np. User-Agent lub Accept). Każdy dodatkowy nagłówek w Vary zwiększa liczbę wariantów w cache.
Specjalne przypadki: GraphQL, agregaty i fragmentacja
GraphQL i inne endpointy, które zwracają dane zależne od zapytań, stanowią wyzwanie:
- Jeśli odpowiedź zależy od treści zapytania (np. różne pola w GraphQL), cache’owanie całej odpowiedzi per zapytanie może być kosztowne. Rozważ cache’owanie wyników pozycjonowanych do fragmentów lub użycie dedykowanego mechanizmu cache (dataloader, cache per resolver).
- Stosuj apollo cache lub cache fragmentów na CDN, gdy zapytania są często powtarzane.
Monitorowanie, testowanie i metryki
Skuteczna polityka cache wymaga monitoringu i testów. Mierz:
- Hit ratio — odsetek trafień w cache vs missów.
- Średni czas odpowiedzi i przepustowość przy hitach/missach.
- Częstość invalidacji i koszty związane z purge.
Warto posiadać testy integracyjne symulujące różne scenariusze (uwierzytelniony ruch, ruch anonimowy, aktualizacje danych) oraz testy obciążeniowe, by sprawdzić, czy polityki cache nie prowadzą do nieoczekiwanych zachowań.
Najlepsze praktyki i checklist
Podstawowa lista kontrolna przy konfiguracji cache:
- Zidentyfikuj, które endpointy mogą być cache’owane (GET/HEAD) i które nie.
- Ustal domyślną politykę Cache-Control i dostosuj ją per endpoint.
- Wdroż ETag lub Last-Modified dla warunkowej rewalidacji.
- Użyj s-maxage dla CDN i public/private dla kontroli współdzielonego cache.
- Planuj mechanizmy invalidacji (purge, wersjonowanie URL, krótkie TTL).
- Monitoruj hit ratio i optymalizuj klucze cache oraz Vary.
- Bezpieczeństwo: nie cache’uj danych wrażliwych i uważaj na Authorization/Set-Cookie.
Wdrożenie krok po kroku
Prosty plan implementacji:
- Krok 1: Audyt endpointów — które zwracają statyczne/dynamiczne/indywidualne dane.
- Krok 2: Ustal polityki Cache-Control i walidatory (ETag/Last-Modified).
- Krok 3: Wdróż konfigurację na serwerze oraz w CDN z różnymi s-maxage w razie potrzeby.
- Krok 4: Przetestuj scenariusze: pierwszy request (miss), kolejny (hit), zmiana zasobu (purge + miss), warunkowe GET (304).
- Krok 5: Monitoruj i optymalizuj na podstawie metryk.
Przykłady błędów do uniknięcia
Typowe pomyłki:
- Brak walidatora (ETag/Last-Modified) przy krótkim max-age — powoduje pełne pobieranie przy każdym odświeżeniu.
- Ustawienie public dla treści spersonalizowanych — ryzyko wycieku danych użytkowników.
- Nieprzemyślane użycie Vary — prowadzi do eksplozji wpisów w cache i niskiego hit ratio.
- Ignorowanie wpływu cookies i Authorization na cache key.


