Short Guide for Modern HTTP Caching
Controls how responses should be cached.
Do NOT cache the response.
Cache-Control: no-store
Revalidate cache before use (see Cache Revalidation for more info).
Browser will send a request to validate if the cached data can be used. This can reduce bandwidth but still requires a roundtrip to validate the cached response.
Cache-Control: no-cache
Set the maximum amount of time (in seconds) that the resource will be cached.
Browser will use cached response without sending any request (from disk cache).
Cache-Control: max-age=3600
Response can be cached in shared cache (Reverse Proxy, CDN, etc.)
Note: most of the time, you don’t need to use
public
as it can be inferred by other caching directives, such asmax-age
. But check with CDN document first.
Cache-Control: max-age=3600
equals to
Cache-Control: public, max-age=3600
Response is intended for one user CAN NOT be cached in shared cache.
Cache-Control: private, max-age=3600
Prevents cache revalidation when clicking Refresh button (which normally causes revalidation on all resources).
Cache-Control: max-age=31536000, immutable
Cache-Control: public, max-age=31536000, immutable
Cache-Control: no-store
Why not no-cache
?
Because MPA server usually send Set-Cookie
to rolling cookie expiration time,
and 304 Not Modified
should not send other header than cache information.
RFC 7372 - Section 4.1
Cache-Control: no-cache
Cache-Control: no-cache
Last-Modified and ETag can be used for conditional requests, but not included in this article.
When no-cache
directive is used,
at least one of these headers must be set to trigger cache revalidation.
Time that the resource has been last modified.
Normally used for static files.
Last-Modified: <day-name>, <day> <month> <year> <hour>:<minute>:<second> GMT
ex.
Last-Modified: Tue, 18 Sep 2018 11:12:03 GMT
If browser has cached the response, it will send a request to validate cache with
If-Modified-Since: Tue, 18 Sep 2018 11:12:03 GMT
If the server has a newer file, then it sends the new file contents and new Last-Modified
header
HTTP/1.1 200 OK
Date: Tue, 18 Sep 2018 22:00:00 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 7
Last-Modified: Tue, 18 Sep 2018 20:00:00 GMT
Content
If file has not been modified since, then it returns 304 status code without body.
HTTP/1.1 304 Not Modified
Date: Tue, 18 Sep 2018 22:00:00 GMT
Like Last-Modified
but ETag
has more accuracy.
Used when server does not know resource's last modified date or when a resource could change more than once in a second.
ETag is like a fingerprint of resource, and a server must generate a new ETag when the resource’s contents changed.
ETag can be generated using hash of response body, UUID, or anything that results in a unique string when resource contents changed.
Browser will send If-None-Match
to server to validate cache.
ETag has Weak
and Strong
validator.
A weak ETag is used to validate only body of response, when response body changed, ETag value will change.
ETag: W/"value"
Example
ETag: W/"abcde"
A strong ETag is used to validate both response body and headers.
Even if body is not changed but header is changed, a strong ETag must be changed to a new value.
Use-cases: To cache byte-range response.
ETag: "value"
Example
ETag: "abc1" # for gzip
ETag: "abc2" # for br
ETag 1 | ETag 2 | Strong Comparison | Weak Comparison |
---|---|---|---|
W/"1" | W/"1" | no match | match |
W/"1" | W/"2" | no match | no match |
W/"1" | "1" | no match | match |
"1" | "1" | match | match |
(from RFC-7232)
Use Strong ETag unless you know what you're doing 😁
Ex. you don't care about
Content-Encoding
Content-Language
Range
Set-Cookie
Vary
- etc.
then you can use Weak ETag