Vary: a fejléc, ami megmondja a CDN-nek, mikor nem ugyanaz a válasz

A Vary nem a cache lejáratát, hanem a cache-kulcsot módosítja. Megmutatjuk, miért kell az Accept-Language mellé, és miért hibás a Vary: Cookie.

Egy CDN vagy reverse proxy első közelítésben URL alapján tudja elővenni a korábbi választ. Ez akkor kevés, ha a /termekek tartalma a kérés valamelyik fejléce szerint változik: más nyelv, más képformátum vagy tömörítés jár a kliensnek. A Vary válaszfejléc mondja meg a cache-nek, hogy mely kérésfejlécek voltak részei ennek a döntésnek. Nem a cache érvényességét szabályozza, hanem a cache-kulcsot pontosítja.

Két Accept-Language értékhez két külön CDN cache-kulcs és nyelvi válasz tartozik

Nem „egy URL, egy cache-bejegyzés”

Ha a szerver az Accept-Language alapján magyar vagy angol feliratokat küld, a két válasz ugyanahhoz az URL-hez tartozik, de nem cserélhető fel. A Vary: Accept-Language ezért azt jelenti: a cache a cél-URL mellé ezt a kérésfejlécet is vegye figyelembe. Az RFC 9111 4.1. szakasza szerint a tárolt válasz csak akkor használható újra ellenőrzés nélkül, ha a Vary-ban megnevezett fejlécek egyeznek az eredeti kérésével.

Ez nemcsak nyelvnél fontos. A szerver vagy az előtte lévő CDN gyakran az Accept-Encoding alapján választ br, gzip vagy tömörítetlen reprezentációt; ilyenkor ehhez a döntéshez is tartoznia kell a Vary: Accept-Encoding jelzésnek. Ugyanez a szabály a Client Hints által befolyásolt erőforrásokra is: ha a válasz valóban a hinttől függ, annak a fejlécnek a cache-kulcsban is helye van.

Egy szándékosan kicsi Node-példa

A példa két nyelvi JSON-változatot küld, ezért pontosan egy változó fejléce van. A Node setHeader() API-ja a válasz elküldése előtt állítja be a fejlécet.

import { createServer } from 'node:http';

const server = createServer((req, res) => {
  const acceptLanguage = req.headers['accept-language']?.toLowerCase() ?? '';
  const isHungarian = acceptLanguage.startsWith('hu');

  res.setHeader('Content-Type', 'application/json; charset=utf-8');
  res.setHeader('Cache-Control', 'public, max-age=300');
  res.setHeader('Vary', 'Accept-Language');
  res.end(JSON.stringify({ label: isHungarian ? 'Kosár' : 'Cart' }));
});

server.listen(4173, '127.0.0.1');

A lényeg nem a nyelvfelismerő három sora. Ha ezt a Vary-t elhagynánk, egy megosztott cache kiszolgálhatná az elsőként eltárolt „Kosár” választ egy angol kérésre is. A fordított hiba is gyakori: bekerül a Vary-ba egy olyan fejléc, amely valójában nem befolyásol semmit. Ezzel felesleges, egymástól elkülönült cache-bejegyzéseket hozunk létre, és romlik a találati arány.

A Cookie nem cache-stratégia

Elsőre biztonságosnak tűnhet a Vary: Cookie: így két munkamenet biztosan nem ugyanazt a bejegyzést kapja. Gyakorlatban viszont a teljes Cookie fejléc nagyon sokféle, tehát szinte feladja a megosztott cache hasznát. Ennél fontosabb, hogy egy cookie jelenléte önmagában nem tesz egy választ priváttá. Személyre szabott, bejelentkezés utáni válasznál a helyes alapjelzés a Cache-Control: private; érzékeny adatnál mérlegeld a no-store-t is. A Vary azt írja le, hogyan különülnek el a variánsok, nem azt, hogy egy megosztott cache tárolhatja-e a választ.

Hasonlóan rossz általános megoldás a Vary: User-Agent. A User-Agent értékek sokfélesége gyorsan szétaprózza a cache-t; az MDN cache-útmutatója inkább feature detectiont vagy más, stabilabb felosztást javasol. Ha egy nyelv vagy képminőség fontos része az erőforrás azonosításának, gyakran áttekinthetőbb külön URL-t adni neki, például /hu/termekek vagy egy képméreteket jelölő útvonal formájában.

Mit ellenőrizz deploy előtt?

  • Írd össze, mely kérésfejlécek befolyásolják ténylegesen a body-t vagy a reprezentációt.
  • Csak ezeket tedd a Vary-ba, és minden variánson következetesen ugyanazt küldd; ez a 304-es válaszokra is vonatkozik.
  • Személyre szabott válasznál ne a Vary: Cookie-ra építs: legyen explicit private vagy indokolt esetben no-store.
  • Nézd meg a CDN konfigurációját is: a proxy által hozzáadott tömörítés vagy képkonverzió saját Vary-igényt teremthet.

A Vary: * nem rövidítés erre a problémára: azt jelzi, hogy a döntést nem felsorolható kérésfejlécek befolyásolták, ezért a cache nem használhatja újra a tárolt választ friss ellenőrzés nélkül. A jó Vary-lista kicsi és megmagyarázható: pontosan az a néhány fejléc szerepel rajta, amelytől a bájtok tényleg megváltoznak.

Források

Leave a Reply

Az e-mail címet nem tesszük közzé. A kötelező mezőket * karakterrel jelöltük