- The server uses the ETag HTTP header to communicate a validation token.
- The validation token enables efficient resource update checks:no data transferred if the resource has not changed.
Ensure that the server is providing the necessary ETag tokens. Check your server documentation for the necessary configuration flags.
Cache-Control
- Each resource can define its caching policy via the Cache-Control HTTP header.
- Cache-Control directives control who can cache the response, under which conditions, and for how long.
“no-cache” and “no-store”
“no-cache” indicates that the returned response can’t be used to satisfy a subsequent request to the same URL without first checking with the server if the response has changed. As a result, if a proper validation token (ETag) is present, no-cache incurs a roundtrip to validate the cached response, but can eliminate the download if the resource has not changed.
By contrast, “no-store” is much simpler. It simply disallows the browser and all intermediate caches from storing any version of the returned response—for example, one containing private personal or banking data. Every time the user requests this asset, a request is sent to the server and a full response is downloaded.
“public” vs. “private”
If the response is marked as “public”, then it can be cached, even if it has HTTP authentication associated with it, and even when the response status code isn’t normally cacheable. Most of the time, “public” isn’t necessary, because explicit caching information (like “max-age”) indicates that the response is cacheable anyway.
By contrast, the browser can cache “private” responses. However, these responses are typically intended for a single user, so an intermediate cache is not allowed to cache them. For example, a user’s browser can cache an HTML page with private user information, but a CDN can’t cache the page.
“max-age”
This directive specifies the maximum time in seconds that the fetched response is allowed to be reused from the time of the request. For example, “max-age=60” indicates that the response can be cached and reused for the next 60 seconds.
Define optimal Cache-Control policy
Invalidating and updating cached responses
- Locally cached responses are used until the resource “expires.”
- Embedding a file content fingerprint in the URL enables you force the client to update a new version of the response.
- Each application needs to define its own cache hierarchy for optimal performance.
All HTTP requests that the browser makes are first routed to the browser cache to check whether there is a valid cached response that can be used to fulfill the request. If there’s a match, the response is read from the cache, which eliminates both the network latency and the data costs that the transfer incurs.
How do you get the best of both worlds: client-side caching and quick updates? You change the URL of the resource and force the user to download the new response whenever its content changes. Typically, you do this by embedding a fingerprint of the file, or a version number, in its filename—for example, style.x234dff.css.
Caching checklist
- Use consistent URLs:if you serve the same content on different URLs, then that content will be fetched and stored multiple times.
- Ensure that the server provides a validation token (ETag): validation tokens eliminate the need to transfer the same bytes when a resource has not changed on the server.
- Identify which resources can be cached by intermediaries: those with responses that are identical for all users are great candidates to be cached by a CDN and other intermediaries.
- Determine the optimal cache lifetime for each resource:different resources may have different freshness requirements. Audit and determine the appropriate max-age for each one.
- Determine the best cache hierarchy for your site:the combination of resource URLs with content fingerprints and short or no-cache lifetimes for HTML documents allows you to control how quickly the client picks up updates.
- Minimize churn: some resources are updated more frequently than others. If there is a particular part of a resource (for example, a JavaScript function or a set of CSS styles) that is often updated, consider delivering that code as a separate file. Doing so allows the remainder of the content (for example, library code that doesn’t change very often), to be fetched from cache and minimizes the amount of downloaded content whenever an update is fetched.