Frontend Development 20 min read

Mastering HTTP Caching: From Expires to ETag and Browser Refresh Strategies

This article explains the essential HTTP caching headers—Expires, Cache‑Control, Pragma, Last‑Modified, and ETag—their priorities, how browsers validate cached resources, and the impact of different refresh actions (URI entry, F5, Ctrl+F5) on cache behavior, offering practical guidance for optimal web performance.

Tencent IMWeb Frontend Team
Tencent IMWeb Frontend Team
Tencent IMWeb Frontend Team
Mastering HTTP Caching: From Expires to ETag and Browser Refresh Strategies

Introduction

Fetching content over the network is slow and costly because large responses require multiple round‑trips between client and server, delaying when the browser can use the data and increasing data costs for visitors. Therefore, caching and reusing previously fetched resources is a key performance optimization.

HTTP Header Fields Related to Caching

The RFC2616 specification defines 47 HTTP header fields, of which several are directly related to caching. They can be grouped into four categories:

General headers

Request headers

Response headers

Entity headers

Stone Age Caching (HTTP/1.0)

In the HTTP/1.0 era, caching was controlled by two headers:

Pragma

and

Expires

. Although largely obsolete, they are still seen for backward compatibility.

Pragma

If

Pragma: no-cache

is present, the client must revalidate the resource on every request. This header has higher priority than

Cache-Control

.

<code>Cache-Control: public, max-age=86400
Pragma: no-cache</code>

Expires

Expires

specifies an absolute GMT date after which the resource is considered stale. If the client’s clock differs from the server’s, the expiration may be inaccurate.

<code>Expires: Fri, 11 Jun 2021 11:33:01 GMT</code>

Cache‑Control (HTTP/1.1)

HTTP/1.1 introduced

Cache-Control

to define freshness using relative time intervals, solving the clock‑sync issue of

Expires

. When both

Expires

and

Cache-Control

appear,

Cache-Control

wins. The priority order is Pragma → Cache‑Control → Expires .

Typical directives include:

max-age
no-cache
must-revalidate
<code>Cache-Control: max-age=3600, must-revalidate</code>

Validation Headers

Last‑Modified

The server returns the last modification time of the resource. The client sends it back in

If-Modified-Since

. If unchanged, the server replies with

304 Not Modified

and no body.

<code>Last-Modified: Fri, 22 Jul 2016 01:47:00 GMT</code>

ETag

The server generates a unique identifier (e.g., an MD5 hash) for the resource and returns it in the

ETag

header. The client includes this value in

If-None-Match

. A matching ETag also results in a

304

response.

<code>ETag: "5d8c72a5edda8d6a:3239"</code>

Header Comparison

Expires : simple, uses absolute time, vulnerable to client‑server clock differences.

Cache‑Control : uses relative time, richer options, but only supported by HTTP/1.1.

Last‑Modified : avoids version issues, but any file change triggers a fresh response even if content is unchanged.

ETag : most precise, can detect multiple changes within a second, but adds computational overhead and requires consistent generation across distributed servers.

User Refresh / Access Behaviors

Three common ways to reload a page have different cache effects:

Enter URL in the address bar and press Enter – the browser may serve the resource from cache without contacting the server if it is still fresh.

Press F5 or click the refresh button – the browser forces a request, adding

Cache-Control: max-age=0

and

If-Modified-Since

(or

If-None-Match

) to validate freshness. A

304

response is typical.

Press Ctrl+F5 – the browser bypasses all caches, sending no validation headers, resulting in a full

200

response with the resource.

Caching Practice

In real projects, it is common to send both

Expires

and

Cache‑Control

for maximum compatibility, and to include either

Last‑Modified

or

ETag

(or both) for validation.

Static assets are often versioned (e.g., by appending an MD5 hash to the filename or query string) so that a change automatically creates a new URL, forcing browsers to fetch the updated file while allowing long cache lifetimes for unchanged assets.

Conclusion

Use

Expires

for HTTP/1.0 compatibility; otherwise prefer

Cache‑Control

.

Choose

ETag

when you need sub‑second change detection; otherwise

Last‑Modified

is sufficient.

Combine a freshness header (

Expires

or

Cache‑Control

) with a validation header (

Last‑Modified

or

ETag

) for robust caching.

Version static files to extend cache lifetimes while ensuring updates are fetched.

References

Various articles and documentation on browser HTTP caching, Last‑Modified, ETag, Expires, Cache‑Control, and refresh behavior.

cachingweb performancehttpcache controlETag
Tencent IMWeb Frontend Team
Written by

Tencent IMWeb Frontend Team

IMWeb Frontend Community gathering frontend development enthusiasts. Follow us for refined live courses by top experts, cutting‑edge technical posts, and to sharpen your frontend skills.

0 followers
Reader feedback

How this landed with the community

login 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.