Symfony 8.2 New Published on

One Cache-Control for the CDN, another for the browser

$response->cacheControl('CDN') writes a CDN-Cache-Control header: the CDN, which you can purge, keeps the page for a long time; the browser doesn't.

Topics covered: HttpFoundationHTTP cache

New in Symfony 8.2 (in development). Between the application and the reader, a response goes through several caches: a CDN, sometimes a proxy, then the browser. They all read the same Cache-Control. Yet they are not equal: you can purge the CDN when an article changes; the browser, never. A page kept for a day by the CDN was also kept by every browser, and a correction published at noon stayed invisible to anyone who had read the page that morning.

Targeted headers

RFC 9213 lets you write, next to Cache-Control, a header meant for a single cache: CDN-Cache-Control for CDNs, or a provider-specific name. The cache that recognizes its header applies it and ignores Cache-Control; the other caches ignore the targeted header. Symfony 8.2 writes them for you:

$response->setMaxAge(0)->setPrivate();

$response->cacheControl('CDN')
    ->setMaxAge(3600)
    ->setStaleWhileRevalidate(60);
Cache-Control: max-age=0, private
CDN-Cache-Control: max-age=3600, stale-while-revalidate=60

stale-while-revalidate lets the CDN serve the stale copy while it fetches a fresh one; stale-if-error lets it serve that copy if the application stops responding.

And to see what the cache does?

The same version adds Cache-Status (RFC 9211) to Symfony's HTTP cache: framework.http_cache.cache_status: 'Symfony' makes every response say whether it came from the cache (Symfony; hit; ttl=58) or from the application (Symfony; fwd=miss; stored). It isn't part of this exercise, but it's the tool to check what you're about to write.

Your task

In JournalController:

  1. An article: the CDN keeps it for a day (86400), with 60 s of stale-while-revalidate and one hour of stale-if-error. The browser revalidates it on every visit: max-age=0, private.
  2. The front page: five minutes at the CDN, one minute everywhere else (public).
  3. The cart doesn't change: it only concerns the browser, and has nothing to tell the CDN.

The “Requests” tab shows the headers of each response.

Where the feature comes from: the original pull request.