HTTP Cache Headers

There are a lot of different HTTP headers that can be used by your website. Right now, we’ll be focussing on a specific subset of these: the cache headers. We’ll show you the ins and outs when it comes to cache headers, so in the future you’ll know how to use them!

What do these headers do?

Any kind of caching would normally work through freshness and validation. Let’s explain what that means. New requests will typically give you a fresh copy of the content instantly served from the cache. A validated representation however will rarely send the entire copy again if it hasn’t changed since you’ve last requested it. In cases where there is no validator present (for example a ETag or Last-Modified header) combined with a lack of freshness info it will usually be considered uncacheable.

How is this accomplished?

There is a range of cache headers and their directives that give explicit instructions to any server, CDN and end-user’s browsers on how the content should be handled cache wise. Combining multiple features can give you the desired results, or they might cause your cache to not function at all because they are used incorrectly. We’ll give you a quick walkthrough of the most common HTTP cache headers, their directives and how you can use them.

Cache-Control: directives

There are multiple directives that can be used to control the Cache Headers functionality. You don’t have to use all of them, so pick the ones you need and leave the others out. These are the most important directives:

max-age

In most uses of the Cache Control headers you will see this directive being used. It states the maximum amount of time in seconds that fetched responses are allowed to be used again from the time when a request is made. For example: max-age=300 indicates that an asset can be reused for the next 300 seconds. This asset can be cached by the browser or any downstream caches from the server for this time period.

s-maxage

The “s-” prefix stands for shared as in shared cache. This directive is explicitly for CDNs among other intermediary caches. This directive overrides the max-age directive and expires header field when present. It is important to remember that this directive will not affect visitors browsers. So you can use different values for mag-age and s-maxage to specify different cache timings for both visitors and CDNs.

no-cache

The no-cache directive shows that returned responses can’t be used for subsequent requests to the same URL before checking if server responses have changed. With a proper ETag (also known as a validation token) present as a result, no-cache incurs a roundtrip in an effort to validate cached responses. Caches can however eliminate downloads if the resources haven’t changed. This means that web browsers might cache the assets but they have to check on every request if the assets have changed (the server will return a HTTP 304 response if nothing has changed).

no-store

Different from no-cache, the no-store directive is simpler. This is because it disallows browsers and all intermediate caches from storing any versions of returned responses – such as responses containing private/personal information or banking data. Every time users request this asset, requests are sent to the server. The assets are downloaded every time.

public

If a response is marked public it can be cached even in cases where it is associated with an HTTP authentication or the HTTP response status code is not cacheable normally. Since explicit caching information, for example through the max-age directive, shows that a response is cachable anyway using this directive usually isn’t necessary.

In most cases, a response marked public isn’t necessary, since explicit caching information (e.g. max-age) shows that a response is cacheable anyway.

private

A response marked private can be cached by the browser. These responses are however typically intended for single users hence they aren’t cacheable by intermediate caches (e.g. HTML pages with private user info can be cached by a user’s browser but not by a CDN).

expires

Some time ago this header was used for the levering the caching mechanisms. This header simply contains a date-time stamp. It’s still useful for old user agents but it’s important to note that Cache-Control headers, max-age and s-maxage still take precedence on most modern systems.

last-modified

This header is one of the most common validators for cache. It indicates when a requested resource was last changed. Even though it’s one of the most common validators, it origins date back to the HTTP/1.0 era, making it seen as a legacy validator by some.

ETag

A newer validation method is the usage of ETags. This has become the standard since HTTP/1.1. This is validated through a ETag header field. Usually it’s based on a hash of the content requested, but that doesn’t have to be the case. The client requesting it doesn’t need to have any knowledge of how it’s generated though. If a client has an object in his cache that has expired it can use the ETag to send an HTTP request to the server. The server will then check this token against cached assets. If the asset hasn’t changed the server can return a 304 Not Modified response to the client. This will regenerate the lifespan of the cached asset, instead of resulting in re-downloading the asset.