Understanding HTTP Caching: Strong and Conditional Cache with Node.js Examples

This article explains the fundamentals of HTTP caching, covering strong and conditional cache mechanisms, the relevant response headers, and provides practical Node.js/Express code samples to demonstrate how browsers handle cache validation and expiration.

政采云技术
政采云技术
政采云技术
Understanding HTTP Caching: Strong and Conditional Cache with Node.js Examples

Preface

HTTP caching is a crucial knowledge point for front‑end engineers. This article gives a complete walkthrough of the caching process, aiming to provide readers with a solid overall understanding after reading.

Strong Cache

Strong cache does not require a request to the server; the browser reads the locally stored resource. In Chrome the network status is 200. Strong cache is divided into Disk Cache and Memory Cache, controlled by the browser. Whether a response is strongly cached depends on three header fields: Expires, Cache‑Control and Pragma.

Expires

The Expires value is an HTTP date. The browser compares the current system time with this date; if the system time exceeds the date, the cache is considered stale. Its priority is the lowest among the three headers.

Cache‑Control

Cache‑Control

is introduced in HTTP/1.1 and can appear in both request and response headers. Common directives include:

max‑age: seconds after which the cache expires.

no‑cache: forces revalidation with the server.

no‑store: disables all caching.

private: only the end user may cache.

public: proxies and CDNs may cache.

must‑revalidate: cache may be used until it expires, after which revalidation is required.

Pragma

Pragma

only supports the no‑cache directive, which has the same effect as Cache‑Control: no‑cache and the highest priority among the three headers.

Local verification of the three strong‑cache headers using Express:

const express = require('express');
const app = express();
var options = {
  etag: false, // disable conditional cache
  lastModified: false, // disable conditional cache
  setHeaders: (res, path, stat) => {
    res.set('Cache-Control', 'max-age=10'); // strong cache expires after 10 seconds
  },
};
app.use(express.static(__dirname + '/public', options));
app.listen(3000);

The first load sends a request, the response includes Cache‑Control: max-age=10. Subsequent loads within 10 seconds use the strong cache without a network request. After the timeout, the browser revalidates and the cache is refreshed.

Conditional (Negotiated) Cache

When strong cache expires or the request explicitly bypasses it, the browser may send If‑Modified‑Since or If‑None‑Match headers. If the server validates the resource as unchanged, it returns 304 Not Modified and the browser loads the cached copy. The response will contain Last‑Modified or ETag headers.

ETag / If‑None‑Match

An ETag is a hash that uniquely identifies a resource version. If the server’s file changes, the hash changes. The client sends If‑None‑Match with the previous hash; a match results in a 304 response. Weak validators start with W/ and only trigger when the content truly changes.

Last‑Modified / If‑Modified‑Since

Last‑Modified

holds the file’s last modification timestamp. The client sends If‑Modified‑Since with that timestamp on subsequent requests. If the timestamps match, the server returns 304.

Local verification of conditional cache using Express (ETag enabled, Last‑Modified disabled):

const express = require('express');
const app = express();
var options = {
  etag: true, // enable conditional cache
  lastModified: false, // disable Last‑Modified based cache
  setHeaders: (res, path, stat) => {
    const data = require('fs').readFileSync(path, 'utf-8');
    const hash = require('crypto-js').MD5(JSON.stringify(data));
    res.set({
      'Cache-Control': 'max-age=00', // bypass strong cache
      'Pragma': 'no-cache', // bypass strong cache
      'ETag': hash,
    });
  },
};
app.use(express.static(__dirname + '/public', options));
app.listen(4000);

First request receives the generated ETag. Subsequent requests include If‑None‑Match; if the file content is unchanged, the server returns 304 even if the file’s modification time changed.

Compared with Last‑Modified, ETag solves two problems:

If a file changes more frequently than one second, Last‑Modified may incorrectly return 304.

If a file’s content does not change but its timestamp does, Last‑Modified may still return 304, which is undesirable; ETag avoids this.

Summary

In real‑world scenarios such as the official website of Zhengcai Cloud, static resources like images, infrequently changed JavaScript files, etc., use caching to improve page load speed. Understanding the full HTTP caching flow enables developers to verify and fine‑tune caching behavior with Node.js.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

Node.jscachingHTTPExpress
政采云技术
Written by

政采云技术

ZCY Technology Team (Zero), based in Hangzhou, is a growth-oriented team passionate about technology and craftsmanship. With around 500 members, we are building comprehensive engineering, project management, and talent development systems. We are committed to innovation and creating a cloud service ecosystem for government and enterprise procurement. We look forward to your joining us.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.