Cache-Control — en HTTP-header som definierar cachelagringsregler för resurser på klientsidan, proxyservrar och CDN med hjälp av en uppsättning direktiv. Till skillnad från den föråldrade Expires-header stödjer Cache-Control dussintals kombinationer: max-age anger livslängden i sekunder, private och public hanterar cachetillgänglighet, no-cache och no-store — tvungen kontroll. Enligt Google Web Dev (2025) kan korrekt konfiguration av Cache-Control minska laddningstiden för sidor med 50-80% för återkommande besök. Detta gör headern kritisk för prestandan hos webb- och mobilapplikationer.
Huvudpunkter
Cache-Control — en HTTP-header, standardiserad i HTTP/1.1 (RFC 7234), som gör det möjligt för servern att ange hur och hur länge klienter, proxyservrar och CDN:er får cachelagra svaret. Till skillnad från Expires (HTTP/1.0) använder Cache-Control direktiv — textkommandon som kombineras med kommatecken: Cache-Control: public, max-age=3600, must-revalidate. Headern ger fin kontroll över varje länk i cachelagringskedjan.
Cachning är en av de grundläggande prestandamekanismerna för webben och mobila applikationer. Utan den skulle varje användarbegäran gå direkt till servern, vilket orsakar överdriven belastning och fördröjningar. Cache-Control definierar tre cachenivåer: webbläsare/app (private cache), proxyservrar (shared cache) och CDN (distributed cache). Varje nivå tolkar direktiven på sitt eget sätt.
Felaktig konfiguration av Cache-Control är en av de vanligaste orsakerna till prestandaproblem. För aggressiv cachning gör att användare ser föråldrade data. För svag cachning leder till överdrivna serverförfrågningar och långsam laddning. Enligt Akamai (2025) minskar optimering av Cache-Control för statiskt innehåll serverbelastningen med 70-90% och förbättrar laddningstiden med 40-60% för mobila användare.
Cache-Control dök upp i HTTP/1.1 (RFC 2616, 1999) som en ersättning för Expires. Expires hade ett grundläggande problem: den använde ett absolut datum som berodde på serverns och klientens tidszon. Cache-Control löste detta problem genom att gå över till relativ tid (max-age i sekunder från mottagandet av svaret). Senare lades i RFC 7234 (2014) nya direktiv till: immutable för statiska filer, stale-while-revalidate och stale-if-error för fördröjd kontroll.
Cache-Control omfattar över 10 direktiv indelade i tre grupper: begärandedirektiv (klient → server), svar direktiv (server → klient) och tillägg. I praktiken används i mobil utveckling 6-7 grundläggande svar direktiv som täcker 95% av cachelagringsscenarierna. Låt oss gå igenom var och en med exempel och rekommendationer.
| Direktiv | Betydelse | Exempel |
|---|---|---|
| max-age | Livslängd i sekunder från svarstillfället | max-age=3600 — 1 timme |
| s-maxage | max-age för shared cache (proxy, CDN) | s-maxage=86400 — 1 dag för CDN |
| public | Tillåter cachning för alla (inklusive proxy) | public, max-age=3600 |
| private | Tillåter cache endast för webbläsare/app | private, max-age=600 |
| no-cache | Använd inte utan kontroll (304 obligatorisk) | no-cache |
| no-store | Förbjud cachning helt | no-store |
| must-revalidate | Efter max-age, måste kontrollera hos origin | max-age=3600, must-revalidate |
| immutable | Resursen ändras inte (för versionshanterade statiska filer) | max-age=31536000, immutable |
max-age — det viktigaste direktivet. Det förbjuder klienten att skicka en begäran till servern under en angiven tidsperiod. För statiska filer (CSS, JS, bilder) ställs max-age vanligtvis in från 1 dag till 1 år. För API-svar — från 0 sekunder (alltid färska data) till 5-10 minuter (referensdata). s-maxage gör det möjligt att ställa in olika livslängder för CDN och webbläsare: CDN lagrar kopian 1 dag, webbläsaren — 1 timme.
Dessa två direktiv förväxlas ofta. no-cache förbjuder inte cachning — det kräver kontroll av den cachade kopian vid varje användning genom en villkorlig begäran (If-Modified-Since eller If-None-Match). Om servern svarar 304 — använder klienten cachen. Om 200 — uppdaterar. no-store å andra sidan förbjuder helt lagring av svaret i någon cache, inklusive disk och arbetsminne. Använd no-store endast för känsliga data — tokens, betalningsinformation, personliga dokument.
Expires-headern (HTTP/1.0) anger också resursens livslängd men använder ett absolut datum: Expires: Thu, 03 Jul 2026 12:00:00 GMT. Cache-Control max-age — relativ tid från svarstillfället. Skillnaden är kritisk för distribuerade system: om servern och klienten befinner sig i olika tidszoner kan Expires tolkas felaktigt. Cache-Control har inte detta problem — 3600 sekunder är alltid 3600 sekunder.
När båda headers är närvarande har Cache-Control prioritet framför Expires. Detta definieras i RFC 7234: “Om svaret innehåller Cache-Control med direktivet max-age, MÅSTE mottagaren ignorera Expires”. I praktiken rekommenderas att inte returnera Expires för moderna klienter, eftersom Cache-Control täcker alla scenarier som Expires gör. För bakåtkompatibilitet med gamla proxyservrar och webbläsare kan dock båda headers returneras.
Expires har främst funnits kvar för statiskt innehåll på Nginx och Apache — dessa servrar lägger automatiskt till båda headers. Om du i ditt projekt stöter på Expires utan Cache-Control, ersätt det med Cache-Control med max-age: precisionen i cachehanteringen ökar och beroendet av tidszonen elimineras. För migrering räcker det att konfigurera servern att lägga till Cache-Control istället för Expires.
# Nginx: Cache-Control för statiska filer
location ~* \.(jpg|jpeg|png|gif|ico|css|js)$ {
expires 30d;
add_header Cache-Control "public, immutable, max-age=2592000";
}
# Olika policys för olika innehållstyper
location /api/config {
expires -1;
add_header Cache-Control "no-cache, must-revalidate";
}
location /api/static-data {
expires 5m;
add_header Cache-Control "public, max-age=300";
}
I Nginx-konfigurationen för statiska filer (CSS, JS, bilder) ställs Cache-Control in på 30 dagar med attributet immutable — detta attribut informerar webbläsaren om att resursen aldrig ändras under denna URL (versionshantering via hash i filnamnet). API-slutpunkter använder no-cache för dynamisk data och public med kort max-age för referensdata — ofta efterfrågade och sällan ändrade listor.
I mobila applikationer spelar Cache-Control en speciell roll på grund av begränsningarna i mobila nätverk: hög latens, instabil anslutning, trafikbegränsningar. Korrekt cachning gör det möjligt för användaren att se data omedelbart, även offline, och uppdatera dem i bakgrunden. OkHttp på Android och URLSession på iOS har inbyggda cachesystem som tar hänsyn till Cache-Control.
OkHttp använder CacheInterceptor som läser Cache-Control från svaret och automatiskt hanterar cachning. Om servern returnerade Cache-Control: max-age=3600 kommer OkHttp inte att skicka en begäran till servern under en timme. Efter att max-age har löpt ut skickar OkHttp en villkorlig begäran med If-Modified-Since och If-None-Match. Konfiguration av cache i OkHttp: OkHttpClient.Builder().cache(Cache(directory, maxSize)).
fun createCachedClient(cacheDir: File): OkHttpClient {
return OkHttpClient.Builder()
.cache(Cache(cacheDir, 10L * 1024 * 1024))
.addNetworkInterceptor { chain ->
val response = chain.proceed(chain.request())
response.newBuilder()
.header("Cache-Control",
"public, max-age=300")
.removeHeader("Pragma")
.build()
}
.build()
}
Koden skapar en OkHttpClient med en cache på 10 MB och åsidosätter Cache-Control via NetworkInterceptor. Om servern inte returnerar Cache-Control eller använder Expires, lägger interceptor till public, max-age=300 (5 minuter). Interceptor tar bort den föråldrade Pragma-headern (HTTP/1.0) för kompatibilitet. Enligt samma schema fungerar cachning på iOS via URLCache.shared med konfiguration av memoryCapacity och diskCapacity.
Direktivet stale-while-revalidate gör det möjligt för användaren att se föråldrad cache (stale) medan appen laddar färska data i bakgrunden. Detta ger en omedelbar svarskänsla: användaren ser innehållet direkt och efter en sekund uppdateras det. Stöds av OkHttp från version 3.10 och URLCache på iOS 14+. Exempel: Cache-Control: max-age=3600, stale-while-revalidate=300 — 1 timme aktuell cache, sedan 5 minuters visning av föråldrad cache med bakgrundsuppdatering.
Olika resurstyper kräver olika cachningsstrategier. Låt oss titta på optimala konfigurationer för typiska scenarier inom mobil utveckling. För statiskt innehåll med hash i filnamnet (bundle.abc123.js) kan max-age ställas in på upp till 1 år med immutable. För API-listor som uppdateras sällan (kataloger, kategorier) — max-age från 5 minuter till 1 timme med stale-while-revalidate.
| Resurstyp | Cache-Control | Förklaring |
|---|---|---|
| Versionshanterad statisk data | public, max-age=31536000, immutable | 1 år, filerna ändras inte (hash i URL) |
| Icke-versionshanterad statisk data | public, max-age=86400, must-revalidate | 1 dag med obligatorisk kontroll efter |
| API: referensdata | public, max-age=600, stale-while-revalidate=60 | 10 minuter cache + 1 minut stale |
| API: användardata | private, max-age=60 | 1 minut, endast för specifik användare |
| API: känslig data | no-store | Helt förbjud cachning |
| HTML-sidor | no-cache, must-revalidate | Kontroll vid varje begäran, 304 vid oförändrad |
Det är viktigt att tänka på säkerheten: för svar som innehåller användarens personuppgifter, ställ alltid in private. Utan detta direktiv kan en offentlig proxyserver (t.ex. företagsproxy) cachelagra svaret och lämna det till en annan användare. För autentiseringstokens och betalningsinformation, använd no-store — även privat cache bör inte spara dessa data på disk.
För att kontrollera korrektheten av Cache-Control, använd Age-headern (hur många sekunder cachen har lagrats) och X-Cache (hit/miss på CDN). I webbläsaren — fliken Network, kolumnen Size visar “from disk cache” eller “304 Not Modified”. Om resursen bör cachelagras men laddas varje gång — kontrollera om servern lägger till Cache-Control: no-cache eller Pragma: no-cache tillsammans med dina direktiv.
Vanliga frågor
max-age fungerar för alla cacheminnen (inklusive webbläsare), s-maxage — endast för shared cache (proxy, CDN). Om s-maxage anges, ignorerar CDN max-age och använder s-maxage. Detta gör det möjligt att ställa in olika livslängder för webbläsare och CDN.
Nej, efter att ett svar med max-age har skickats kommer klienten inte att skicka en begäran förrän timern har löpt ut. För omedelbar ogiltigförklaring av cache måste du ändra resursens URL (lägga till version/hash) och skicka push-meddelanden eller WebSocket-meddelanden för tvungen återställning.
Immutable-direktivet (RFC 8246) informerar webbläsaren om att resursen aldrig kommer att ändras under denna URL. Webbläsaren försöker inte ens skicka en villkorlig begäran vid uppdatering av sidan — den använder cache tills max-age har löpt ut. Fungerar endast med versionshanterade filer.
Googlebot tar hänsyn till Cache-Control: lång cachning snabbar upp återskanning. noindex med snabb cache — ok. no-store kan sakta ner indexering, eftersom Googlebot kommer att ladda sidan från början varje gång. För kort max-age ökar serverbelastningen under skanning.
Via helmet eller middleware: res.set('Cache-Control', 'public, max-age=3600'). För statiska filer, använd express.static med parametern maxAge: express.static('public', {maxAge: '1y'}). För dynamiska rutter — individuellt i varje handler.
Sammanfattning
Vi utvecklar en mobil applikation nyckelfärdigt
IT Sectr skapar iOS- och Android-applikationer för startups och företag sedan 2017. Vi ger dig råd och föreslår den bästa lösningen.
Läs också