Master Browser Caching: Strong vs. Negotiated Cache Explained
This article explains the fundamentals of browser caching, compares strong and negotiated cache mechanisms, shows how Expires and Cache‑Control headers work, provides Java code examples for managing cache, and offers practical tips for avoiding stale resources during development.
1. Basic Understanding of Browser Cache
Browser cache (client‑side cache) is a key technique for web performance optimization, but it also brings challenges. When a resource is requested, the browser first checks HTTP response headers to see if it can serve the resource from its cache without contacting the server.
There are two types of cache:
Strong cache : If the cache is hit, the browser reads the resource directly from its local storage and does not send any request to the server.
Negotiated cache : If strong cache is missed, the browser sends a request to the server; the server can respond that the resource is still valid, allowing the browser to load it from the cache.
Both caches load from the client when hit; the difference is that strong cache never contacts the server, while negotiated cache does.
2. Principles of Strong Cache
When a request hits strong cache, the network panel in Chrome shows a status of 200 and the size as "from cache". Strong cache is implemented via the Expires and Cache‑Control response headers, which define the validity period of a resource.
Expires (HTTP/1.0) specifies an absolute expiration time, e.g.:
The browser stores the resource together with all response headers. On subsequent requests it compares the current time with the Expires value; if the request occurs before the expiration time, the cache is hit.
Cache‑Control (HTTP/1.1) uses a relative time expressed in seconds, e.g. Cache‑Control: max-age=315360000. The workflow is similar: the browser records the response time, adds the max‑age to compute an expiration moment, and compares it with the current request time.
When both headers are present, Cache‑Control takes precedence:
3. Managing Strong Cache
Strong cache can be enabled either by adding headers in application code or by configuring the web server.
Java example:
java.util.Date date = new java.util.Date(); response.setDateHeader("Expires", date.getTime() + 20000); // Expires value response.setHeader("Cache-Control", "public"); // public: both browser and proxy may cache response.setHeader("Pragma", "Pragma"); // enable cachingTo disable strong cache:
response.setHeader("Pragma", "no-cache"); response.setDateHeader("Expires", 0); response.addHeader("Cache-Control", "no-cache"); // prevent cachingTomcat provides an ExpiresFilter for configuring strong cache; nginx and Apache also support expires and cache‑control directives.
Common development‑time solutions for stale resources include:
Press Ctrl+F5 to force a full reload.
Use the browser’s incognito/private mode.
Disable cache in Chrome DevTools Network panel.
Append a version query string to static files, e.g. style.css?v=0.0001.
For iframe‑embedded pages, right‑click and reload the iframe.
Add a random number to AJAX request URLs.
When using static servers from tools like grunt‑contrib‑connect, the server can be configured to send Cache‑Control: no‑cache for all resources.
4. Applications of Strong Cache
Strong cache is the most effective tool for accelerating pages with many static assets. By assigning a far‑future expiration (e.g., year 2026) to CSS, JS, and image files, browsers will load them from local storage after the first request, dramatically reducing load time.
However, this creates a cache‑busting problem when a resource is updated: users who have the old version cached will continue to see the stale asset unless they clear the cache or perform a forced refresh. Solutions include using build tools (grunt, gulp, webpack, fis, edp) to automatically append version hashes to filenames.
5. Principles of Negotiated Cache
If strong cache misses, the browser sends a conditional request. When the server determines the resource is unchanged, it returns 304 Not Modified (no body) and the browser loads the resource from its cache.
Negotiated cache relies on two header pairs:
Last‑Modified / If‑Modified‑Since : The server sends the last modification timestamp; the browser sends it back on subsequent requests.
ETag / If‑None‑Match : The server generates a unique identifier for the resource; the browser returns it on later requests.
Examples of the workflow are illustrated below:
6. Managing Negotiated Cache
Most web servers enable both header pairs by default. In distributed environments, ensure that Last‑Modified timestamps are consistent across machines and consider disabling ETag if it varies per server.
For example, JD.com’s responses include only Last‑Modified without an ETag.
7. Browser Behavior Impact
By default, the browser first checks strong cache, then negotiates cache if needed. User actions can alter this flow: Ctrl+F5 forces a full reload, bypassing both caches. F5 skips strong cache but still checks negotiated cache.
Understanding these mechanisms helps developers control resource freshness and optimize page performance.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
21CTO
21CTO (21CTO.com) offers developers community, training, and services, making it your go‑to learning and service platform.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
