We hebben zojuist ondersteuning toegevoegd voor het lelijkste deel van HTTP: Vary
Dat is niet direct een aanbeveling voor Vary, maar 'lelijk' betekent niet 'nutteloos'.
Eén URL kan namelijk meer dan één correct antwoord hebben. Een server kan bijvoorbeeld verschillende afbeeldingsformaten leveren aan verschillende browsers. Als een cache Vary negeert, riskeert deze de verkeerde bytes aan een verzoek te leveren. Maar als de cache elke ruwe headerwaarde als uniek behandelt, kunnen een handvol vergelijkbare verzoeken uitgroeien tot duizenden cache-items die nauwelijks herbruikbaar zijn. Vary vertelt een cache welke velden in het verzoek invloed kunnen hebben op de respons, maar het vertelt de cache niet welke verschillen daadwerkelijk relevant zijn.
Ondersteuning voor Vary is nu beschikbaar in Cache Rules voor elk abonnement. De origin (de bronserver) geeft nog steeds aan welke request-headers een respons kunnen beïnvloeden, maar jij bepaalt hoe Cloudflare met elk van deze headers omgaat. Je kunt bekende onderhandelingsheaders (negotiation headers) normaliseren, exacte waarden doorgeven wanneer kleine verschillen ertoe doen, of de cache omzeilen (bypass) wanneer de variatie te onvoorspelbaar is. De origin verklaart wat er kan variëren, en jij bepaalt hoeveel variatie daadwerkelijk betekenisvol is voor de cache.
Hoe Vary werkt
Vary is een standaard HTTP-response-header die tussenliggende caches (zoals Cloudflare) vertelt welke velden in het verzoek invloed kunnen hebben op de respons die door de origin wordt verzonden. Websites gebruiken Vary om verschillende talen, afbeeldingsformaten, compressieschema's of regionale inhoud via dezelfde URL te serveren.
Stel dat één URL twee geldige representaties produceert. Een browser vraagt een webpagina aan:
GET /catalog HTTP/1.1
Host: example.com
Accept: text/html
De origin retourneert HTML en identificeert Accept als een veld dat de respons kan beïnvloeden:
HTTP/1.1 200 OK
Content-Type: text/html
Cache-Control: public, max-age=3600
Vary: Accept
Een API-client kan dezelfde URL aanvragen met een andere voorkeur:
GET /catalog HTTP/1.1
Host: example.com
Accept: application/json
In dit geval is de correcte respons JSON. De header Vary: Accept vertelt de cache dat de URL alleen niet voldoende is om tussen de responsen te kiezen; de waarde van de Accept-header moet ook worden meegewogen.
Zonder Vary zou de respons die als eerste in de cache terechtkomt aan beide cliënten worden geserveerd. Als HTML wint, ontvangt de API-client markup en faalt de JSON-parser. Als JSON wint, ontvangt een browser die een webpagina verwacht een API-respons.
Vary voorkomt dus dat de cache de verkeerde respons naar de client stuurt. Maar het introduceert een moeilijkere vraag: wanneer twee verzoeken verschillende headerwaarden bevatten, hebben ze dan ook echt verschillende responsen nodig?
Wanneer correct cachen nutteloos wordt
Vary kan een cache vertellen welke velden in een verzoek invloed hebben op een respons, maar niet wat de respons representeert. Neem bijvoorbeeld een origin die inhoud alleen in het Engels, Frans en Duits serveert. Een client kan sturen:
Accept-Language: en-US, fr;q=0.8
Terwijl een andere client vraagt:
Accept-Language: fr;q=0.8, en-GB
Beide verzoeken geven hier de voorkeur aan Engels. De respons van de origin kan beide verzoeken koppelen aan exact dezelfde Engelse respons. Maar een cache die de ruwe waarden vergelijkt, kan niet veilig aannemen dat ze equivalent zijn. Ze hebben verschillende volgordes en taalcodes (die de origin niet differentieert). Hierdoor kan de cache ze als aparte varianten opslaan, zelfs als de respons-bodies identieke bytes bevatten.
Dit is het centrale probleem van Vary. Applicaties produceren vaak een kleine, eindige set representaties uit een enorme set mogelijke request-waarden. De origin begrijpt dat duizenden taalvoorkeuren terugvallen op drie ondersteunde talen, terwijl een cache dat meestal niet doet.
Dit probleem verergert wanneer een respons varieert op meerdere velden. Tien mogelijke waarden in één veld creëren tien varianten. Tien waarden over drie velden kunnen 1.000 combinaties creëren. Echte headers kunnen een veel grotere cardinaliteit hebben: User-Agent-waarden zijn talrijk, cookies kunnen uniek zijn per bezoeker, en voorkeursheaders kunnen verschillen in volgorde, opmaak (spaties en tabs tellen!) en kwaliteitswaarden.
Het resultaat is een cache die technisch perfect correct is, maar bijna permanent "koud" blijft (een item wordt nooit hergebruikt). Identieke responsen kunnen verspreid zijn over items die te weinig verkeer ontvangen om "warm" in de cache te blijven. Ze kunnen capaciteit verbruiken, elkaar verdringen, de cache hit ratio verlagen en meer verzoeken terugsturen naar de origin-servers.
Uit een analyse van meer dan 120 miljoen responsen van bijna 50.000 populaire sites bleek dat bijna 3.000 sites varieerden op vier of meer velden. Sommige varieerden op 10, 23 of zelfs 47 velden. We willen ervoor zorgen dat klanten de tools hebben om Vary te gebruiken wanneer dat gepast is, maar niet op zo'n manier dat ze een nutteloze cache creëren.
Sommige variatie met hoge cardinaliteit is bewust. CDN's of reverse proxies kunnen waarden injecteren, zoals een geografische regio, om inhoud voorspelbaar te partitioneren. Dat werkt wanneer de mogelijke waarden gecontroleerd zijn en elk component het eens is over de betekenis. Zonder die beperkingen fragmenteert de cache in varianten die mogelijk nooit worden hergebruikt.
Hoe Cache Rules Vary beheren
Cloudflare-klanten hadden al verschillende manieren om om te gaan met onderhandelde inhoud (negotiated content). Ze konden de cache omzeilen, de onderhandelingslogica van de origin reproduceren in een aangepaste cache key, een Worker gebruiken, of functies als Vary for images gebruiken.
Vary in Cache Rules vult het gat tussen deze functies door de ondersteuning te splitsen in twee beslissingen:
- De origin gebruikt
Varyom de request-headers te identificeren die een respons kunnen beïnvloeden. - De Cache Rule bepaalt hoe Cloudflare de waarde van elke header afhandelt.
Een Cache Rule dwingt niet elke respons om te variëren. Als de origin geen Vary retourneert, cached Cloudflare de respons normaal. Wanneer de origin wel Vary retourneert, gebruikt Cloudflare de geconfigureerde actie voor elke genoemde header. Headers zonder individuele instelling gebruiken de standaardactie van de regel.
Beschikbare acties
| Actie | Wat Cloudflare doet | Beste gebruik voor |
|---|---|---|
| normalize | Normaliseert request-headers voordat een cached variant wordt gekozen. Past specifieke regels toe op Accept, Accept-Language en Accept-Encoding. Voor andere headers verwijdert het optionele witruimte en combineert het herhaalde headerregels in hun oorspronkelijke volgorde. | Aanbevolen startpunt voor onderhandelingsheaders waarbij veel request-waarden leiden tot een kleine set responsen. |
| passthrough | Gebruikt de ruwe bytes van de request-header voor cache-matching (behoudt hoofdletters, witruimte, volgorde en duplicaten). | Headers met een gecontroleerde set waarden, waarbij de exacte waarde de respons verandert. |
| bypass | Slaat de respons niet op in de cache wanneer de origin deze header in Vary noemt. | Gepersonaliseerde headers met hoge cardinaliteit of onvoorspelbare waarden, zoals Cookie of User-Agent. |
We raden normalize aan als standaard. Gebruik bypass voor individuele headers met persoonlijke of onbegrensde waarden. Gebruik passthrough wanneer de exacte waarde de respons verandert.
Ongeacht de geconfigureerde acties, zal Vary: altijd de cache omzeilen (bypass*). Dit betekent namelijk dat elk aspect van het verzoek, zelfs informatie buiten het HTTP-bericht (zoals het IP-adres van de client), invloed kan hebben op de respons.
Hoe een respons door de cache beweegt
Laten we een verzoek naar /catalog volgen:
- Eerste verzoek: Cloudflare heeft geen opgeslagen
Vary-gegevens voor de resource; de cache-lookup faalt (miss). De bijbehorende Cache Rule kan geconfigureerde velden normaliseren voordat Cloudflare contact opneemt met de origin. - Respons van de origin: De origin reageert met
Vary: Accept, Accept-Language. - Opslag: Cloudflare registreert deze headernamen en slaat de respons op als een cached variant. De headerwaarden, verwerkt volgens de Cache Rule, onderscheiden deze variant van andere voor dezelfde resource.
- Tweede verzoek: Cloudflare begint met de basis-cache-sleutel (meestal de URL). Het leest de opgeslagen
Vary-velden en past de Cache Rule toe op die headers in het nieuwe verzoek om de matching cached variant te identificeren. - Matching: Stel dat ze normaliseren naar
Accept: text/htmlenAccept-Language: en,fr. Cloudflare gebruikt deze waarden om direct de matching cached variant op te zoeken.
De loop wordt gesloten door de origin-respons:
- Bevat de respons geen
Vary? Dan wordt deze normaal cached. - Resolveren alle genoemde headers naar
normalizeofpassthrough? Dan kan de respons als cached variant worden opgeslagen. - Gebruikt een van de genoemde velden
bypass? Dan wordt de respons niet opgeslagen. - Bevat de respons
Vary: *? Dan wordt deze niet opgeslagen.
Dit legt een belangrijke verantwoordelijkheid bij de origin: elke cachebare respons die kan verschillen op basis van request-velden moet consequent de juiste Vary-header retourneren, inclusief foutmeldingen en fallback-responsen.
Normalisatie houdt equivalente verzoeken bij elkaar
Terug naar de verzoeken voor Engels en Frans:
Accept-Language: en-US, fr;q=0.8Accept-Language: fr;q=0.8, en-GB
Beide geven de voorkeur aan Engels. Waar passthrough ze als verschillende varianten zou behandelen, reduceert normalize ze beide naar en,fr, waardoor ze een gecachte respons kunnen delen.
Om dit te bereiken, zet Cloudflare waarden in Accept, Accept-Language en Accept-Encoding om naar kleine letters en sorteert ze op kwaliteitswaarde (hoogste eerst), met alfabetische sortering om gelijke waarden te ontknopen. De volgorde van de client heeft dus geen invloed op de cache-sleutel. Daarna verwijdert Cloudflare parameters van items met een nonzero kwaliteitswaarde.
Om de selectie van de origin in lijn te houden met de cache-matching, stuurt Cloudflare de genormaliseerde Accept- en Accept-Language-waarden door naar de origin.
Vary configureren in Cache Rules
In het Cloudflare-dashboard ga je naar Caching > Cache Rules. Maak een regel aan of bewerk deze, maak de respons in aanmerking voor cache en voeg de Vary-instelling toe.
Dezelfde configuratie is beschikbaar via de Rulesets API in de httprequestcache_settings fase. Hieronder volgt een voorbeeld dat Accept en Accept-Language normaliseert naar een geconfigureerde set formaten en talen:
{
"rules": [
{
"ref": "vary_negotiated_content",
"description": "Cache bounded negotiated representations",
"expression": "(http.host eq \"example.com\" and http.request.uri.path eq \"/catalog\")",
"action": "set_cache_settings",
"action_parameters": {
"cache": true,
"vary": {
"default": {
"action": "normalize"
},
"headers": {
"accept": {
"action": "normalize",
"media_types": ["text/html", "application/json"]
},
"accept-language": {
"action": "normalize",
"languages": ["en", "fr", "de"]
}
}
}
}
}
]
}
Na de uitrol adviseren we om de URL te testen met verschillende headerwaarden die naar dezelfde variant zouden moeten normaliseren. Controleer via CF-Cache-Status of je hits krijgt zodra de cache is gevuld.
Waarom geen aangepaste cache-sleutel gebruiken?
Een logische vraag is: "Waarom voeg ik Accept en Accept-Language niet simpelweg toe aan een aangepaste cache-sleutel (custom cache key)?"
Dat werkt wanneer die velden altijd deel uitmaken van de identiteit van de resource. Een aangepaste cache-sleutel voegt de geconfigureerde dimensies echter toe aan elke respons die door de regel wordt gedekt, of de origin ze nu heeft gebruikt of niet.
Vary is respons-gestuurd. Gebruik een aangepaste cache-sleutel wanneer een eigenschap van het verzoek altijd de resource definieert. Gebruik Vary wanneer de origin dezelfde set request-velden declareert over alle cachebare responsen.
Conclusie
Vary helpt een duidelijk probleem op te lossen: één URL kan meer dan één correct antwoord hebben. De uitdaging voor de cache is echter bepalen welke verschillen in het verzoek daadwerkelijk relevant zijn.
Vary in Cache Rules verbindt deze twee perspectieven. De origin identificeert de velden, en jij bepaalt of je waarden normaliseert, exacte verschillen behoudt via passthrough, of de respons buiten de cache houdt via bypass.
Vary in Cache Rules is nu beschikbaar voor Free, Pro, Business en Enterprise-abonnementen via het Cloudflare-dashboard, de Rulesets API en Terraform.
Groetjes,