In this week’s Two Minute Tech Tuesday, we're talking about the Cache-Control header which is returned by the origin web server to control the cacheability, scope, expiration and revalidation of cached objects.
The cache-control header is an HTTP response header, sometimes even a request header. It's part of conventional HTTP caching standards that are widely adopted by both web clients and caching proxies. Here's an example of an HTTP response containing a set of headers, including the cache-control header.
HTTP/1.1 200 OK
Accept-Ranges: bytes
Cache-Control: public, max-age=600, must revalidate
Content-Encoding: gzip
Content-Length: 230529
Content-Type: text/html; charset=utf-8
Date: Thu, 28 Oct 2021 11:52:25 GMT
Etag: 5d32b2f31d51ace2427a98917ba4a00
Last-Modified: Wed, 27 Oct 2021 15:50:15 GMT
Vary: Accept-Endcoding
How it works:
- When the client sends an HTTP request to the caching proxy for an uncached resource, the proxy will forward that request to the origin, which will respond with an HTTP response that can continue to the cache-control header.
- This cache-control header will be respected by the caching proxy and will decide if it will be cached, and for how long.
- The proxy will forward that response to the client who can choose to respect the cache-control header.
Why implement it?
The purpose of this header is to control the cacheability of resources, the caching scope, the caching expiration, and also the cache revalidation process. As mentioned before, one of its functions is to control cacheability. This can be done with the following syntax:
Cache-Control: public, max-age=600, must revalidate
The above object is cacheable for 600 seconds. But if you use a no-cache, no-store syntax, this implies that the object can not be served from cache and cannot be stored in cache.
Cache-Control: no-cache, no-store
In terms of scope, the public keywords can be used to indicate that both caching proxies and web clients can cache the response, whereas the private keyword only allows web clients to cache response.
When it comes to controlling the expiration of cached objects. The maxage syntax is used to define the time to live. In the above case, both web clients and caching proxies will cache the object for 600 seconds. We can extend this by using the s-maxage syntax, which only applies to shared devices:
Cache-Control: public, max-age=600, s-maxage=3600, must-revalidate
Caching proxies will respect that and will cache the object for 3600 seconds (an hour) and the client may choose to cache for another 600 seconds. When cached objects expire, revalidation needs to take place with the origin.
By using the must-revalidate syntax, you imply that expired objects cannot be served past their expiration time, so staleness is not allowed. However, if you use the stale-while-revalidate syntax, you can indicate the amount of time expired objects can be served past their expiration time, while revalidation takes place.
Cache-Control: public, max-age=600, stale-while-revalidate=100
The stale-if-error syntax determines how long past its expiration time stale objects can be served if the backend responds with an error or is not available at all.
Cache-Control: public, max-age=600, stale-if-error=86400
Cache-control headers and Varnish
When referring to caching proxies, that could just as well be Varnish. It goes without saying that Varnish respects cache-control headers. They offer tremendous power to application developers and allows them to control each individual resource, the cache ability, the expiration the scope and revalidation process. See you next week for more content, and another Two Minute Tech Tuesday.