The labs on this site need JavaScript to run. The same content is written out below.
Learn › Networking › HTTP
HTTP caching and ETag
Do we have to fetch the same file again?
A browser keeps a response it has received and uses it again later. If the server tells it, in the response headers, "how long it may use the response as it is" and "a tag for the version of the content (the ETag)", the browser can skip the request altogether or ask only "has it changed?".
Checked against real execution · Checked with a test server and a real browser
Concepts in this lab
- Conditional requests and ETag
- A kind of request in which the client asks the server whether the data it already has is still current. An ETag is an identifier value that represents the version of a resource. When the client sends this value in a request, the server responds with 304 Not Modified and no body if the resource has not changed. This reduces network use because the same data is not sent again.
- HTTP status codes
- A three-digit number that shows the result of the server's handling of a request. 2xx means success, 3xx means a move to another location (redirection), 4xx means a problem with the client's request, and 5xx means an error on the server side. Common ones are 200 (success), 201 (created), 400 (bad request), 401 (authentication required), 403 (no permission), 404 (not found), and 500 (server error).
- Cache
- Storing frequently used data or computed results ahead of time in a place that can be accessed quickly, and reusing them. Responses get faster and the load on the source drops, because the source (usually a database) is not queried every time. In return, you must manage the problem of stale values that remain when the source changes.
- CDN
- A network that keeps copies of content on servers placed in many regions around the world and has a server close to the user respond. Static files such as images, video, and scripts are delivered faster, and fewer requests go to the origin server.
Try these
- Default settings — The request is made again after the freshness lifetime has passed. If nothing changed, only a 304 comes back, with no body.
- Open again within the freshness lifetime — No request is sent to the server at all.
- If the content changed — The ETag is different, so the new content arrives with 200.
- Content changes within the freshness lifetime — The browser does not know, and it uses the old content.
- no-store — Nothing is stored, so the whole response is received again every time.
- no-cache — The response is stored, but the server is asked every time before it is used.
Running with the default settings
- This is the first time this address is opened. Nothing is stored in the browser, so it sends a request to the server.
- The server sends the 200KB body together with a cache directive. The browser stores the body together with the ETag (a tag that marks the version of the content).
- 120s later, the same address is opened again. The freshness lifetime of 60s has passed. The browser does not throw away what it stored. It asks, "What I have is v1. Is it still the same?"
- The current ETag on the server is "v1" too. Nothing has changed, so the server answers with just 304 and no body. The browser uses the body it stored as it is. It also starts the freshness lifetime again. The 200KB was not sent again.
Result of this run
- A 304 response has no body, so almost nothing is transferred. One round trip still takes place, though, and the server has to do some work to find out the current ETag.
Code
@GetMapping("/products/{id}")
ResponseEntity<Product> get(@PathVariable long id) {
Product p = productService.find(id);
return ResponseEntity.ok()
.cacheControl(CacheControl.maxAge(60, TimeUnit.SECONDS))
.eTag("\"v" + p.getVersion() + "\"") // a tag for the version of the content
.body(p);
}
// If the If-None-Match of the request equals the current ETag,
// Spring responds with 304 Not Modified and no body
Assumptions of this model
The body size of 200KB is an example. The meaning of the cache directives and of conditional requests follows the HTTP caching standard (RFC 9111) and the definition of conditional requests (RFC 9110). The same check can also be done with the last modified time (Last-Modified / If-Modified-Since) instead of the ETag. When the user clicks reload, the browser may send a validation request regardless of the freshness lifetime. It was checked with a local test server and a real browser (Chromium-based), with the freshness lifetime shortened to 2s for the test. A repeated request within the freshness lifetime did not reach the server; after it had passed, If-None-Match was attached and a 304 came back; and when the content had changed, a 200 and the new body came. With no-store, the whole response was received both times, and with no-cache, a conditional request was sent even when the request was repeated immediately. When the content on the server changed within the freshness lifetime, the browser kept using the old content.
Previous lab: Cookies · Next lab: Retries and idempotency