你的浏览器可能比你想象中更"勤俭持家"。这篇文章聊聊它是怎么帮你省流量、省时间的,以及什么时候该阻止它。
你有没有注意过这样一个现象?
第一次打开一个网页,要等好几秒。第二次打开同一个网页,基本秒开。
你是不是以为浏览器記住了这个页面?它到底是怎么做到的?
今天我们来聊聊浏览器缓存——这个你天天在用,却可能从来没认真了解过的机制。
原文地址
墨渊书肆/浏览器到底在偷偷帮你做什么?——HTTP缓存与刷新机制
缓存到底是个什么东西?
想象一下这个场景。
你每天早上都去楼下的早餐店买豆浆。第一次去的时候,老板娘要问你「要甜的還是甜的」「要不要加鸡蛋」「打包还是在这吃」——问半天,你回答半天。
但如果你连着去了一个星期,每天都点「原味豆浆,不加糖,带走」。
第七天的时候,你刚走到门口,老板娘已经把豆浆打包好了递给你,连话都不用说一句。
这就是缓存。
浏览器做的就是这件事。第一次访问一个网页,它要千里迢迢去服务器「要」资源。第二次访问,它就聪明了——直接从自己的「小仓库」里拿出来给你用,省时又省力。
但问题来了:浏览器怎么知道哪些东西可以直接用?哪些东西已经过期了?
这就涉及到HTTP缓存的两个核心概念:强缓存和协商缓存。
强缓存:先用了再说
强缓存就像是你跟浏览器达成的一个小协议。
你告诉它:「这个资源在未来一年内都不会变,你就放心大胆地用,别来问我。」
浏览器听了这话,就直接把资源扔给你,连服务器的大门都不带敲的。
那这个"一年"的承诺是怎么实现的呢?
Expires:看时间
最早的方式是用Expires这个响应头:
Expires: Wed, 21 Oct 2026 07:28:00 GMT
这就像在商品上贴了个过期日期:「2026年10月21日之前都有效。」
但这个方式有个bug:如果你的电脑时间和服务器时间不一致,比如你把电脑调快了一个月,那缓存就直接失效了——浏览器会以为已经过期了,实际上还能用。
Cache-Control:更聪明的做法
后来HTTP/1.1推出了Cache-Control,就像给缓存装了个更智能的计时器:
Cache-Control: max-age=3600, public
max-age=3600的意思是:缓存有效期是3600秒,也就是一个小时。
这个比Expires靠谱多了——它是相对时间,不受系统时间影响。
而且Cache-Control还支持一堆指令,让你能更精细地控制缓存行为:
| 指令 | 意思 | 什么时候用 |
|---|---|---|
public | 缓存可以放在CDN、代理服务器上 | 静态资源 |
private | 只准浏览器自己缓存 | 个性化内容 |
no-cache | 每次用之前先问问我 | 经常变化的资源 |
no-store | 别存了,每次都重新拿 | 敏感数据 |
immutable | 这东西永远不会变 | 版本化后的静态资源 |
这里有个重点:no-cache不是"不缓存",而是"用之前先问一下"。
协商缓存:问一下再决定
强缓存虽然快,但有个问题:如果服务器上的资源已经变了,浏览器可不知道。
你跟浏览器说「这个文件缓存一年」,结果三个月后你更新了网站,浏览器还在用旧的——用户就看不到新内容了。
怎么办?
协商缓存就是这个问题的答案。
它的逻辑是这样的:浏览器还是要去问一下服务器:「我这里有个缓存,还能用吗?」
服务器说「能用」(资源没变),返回304 Not Modified,浏览器继续用缓存。
服务器说「不能用」(资源变了),返回200 OK + 新资源,浏览器更新缓存。
Last-Modified:看修改时间
最早的方式是用Last-Modified:
# 服务器返回
Last-Modified: Wed, 21 Oct 2025 07:28:00 GMT
# 浏览器下次请求
If-Modified-Since: Wed, 21 Oct 2025 07:28:00 GMT
就像你问老板:「这个文件最后改过是什么时候?如果还是那天下午,我就继续用我的版本。」
但这个方式有个缺点:精度只到秒。如果一秒内文件被修改了两次,浏览器可看不出来。
ETag:看"指纹"
后来就有了ETag,它给每个文件生成一个"指纹":
# 服务器返回
ETag: "abc123"
# 浏览器下次请求
If-None-Match: "abc123"
这个指纹通常是文件的MD5哈希值,或者其他能唯一标识内容的东西。
服务器收到请求后,会比较一下ETag:如果指纹一样,说明内容没变, 返回304;如果不一样,返回200 + 新内容。
划重点:ETag的优先级高于Last-Modified。如果服务器同时给了这两个,浏览器会先用ETag。
缓存到底是怎么工作的?
让我给你串起来整个流程:
你访问一个页面
↓
浏览器先看强缓存(Cache-Control / Expires)
↓
[命中了] → 直接从本地拿 → 页面秒开 ✅
↓ [没命中]
浏览器带着缓存标识去问服务器
↓
服务器比较ETag / Last-Modified
↓
[资源没变] → 返回304 → 浏览器用缓存 → 依然很快 ⚡
↓ [资源变了]
服务器返回200 + 新资源 + 新标识
↓
浏览器更新缓存,展示新内容
这个流程你理解之后,很多奇怪的现象就能解释了:
- 为什么更新了CSS但页面没变?——可能被强缓存了
- 为什么F5刷新后还是旧内容?——正常,优先用强缓存
- 为什么Ctrl+F5就变了?——强制刷新,绕过了所有缓存
刷新这件事,讲究这么多?
说到刷新,我发现很多人(包括以前的我)对浏览器的刷新按钮有误解。
你以为的刷新:「重新加载这个页面」
实际上的刷新:「emmm,让我先看看缓存有没有过期」
正常刷新(F5 / 点击链接)
这是最常用的方式。
浏览器会先看强缓存,过期了吗?没有就直接用。过期了就去协商,服务器说能用就用。
结果:可能快(304),也可能慢(200),取决于缓存状态。
强制刷新(Ctrl+Shift+R / Ctrl+F5)
这个才是真正的"重新加载"。
浏览器会跟服务器说:「少废话,把所有资源都给我拿新的,别跟我提缓存!」
请求头里会带上Cache-Control: no-cache,或者直接忽略所有的缓存标识。
结果:总是200,慢但保证最新。
开发者工具里的选项
Chrome DevTools里其实有更精细的控制:
- 禁用缓存:只有DevTools打开时才生效,模拟
no-cache - 硬性重新加载:等于强制刷新
- 空缓存并硬性重新加载:先清空所有缓存,再强制刷新——相当于把浏览器的小仓库一把火烧了
说完了缓存,来聊聊安全
缓存虽好,但有时候也会带来安全问题。
比如你登录了一个网站,浏览器缓存了你的个人信息。然后别人用了你的电脑,打开同一个网站——诶,怎么直接就登录了?
这就是缓存的"副作用"。所以有些东西是不能缓存的。
no-store:敏感数据别存
Cache-Control: no-store
这个指令告诉浏览器:「看归看,但别存到硬盘上。」内存里用完就扔,下次重启就没了。
登录后的用户信息、token、支付相关的数据——这些都应该加上no-store。
private:只存浏览器
Cache-Control: private
这个的意思是:「可以缓存,但只能存在用户自己的浏览器里,别给CDN、代理那些中间商。」
用户信息存private,静态资源存public——这是基本的安全常识。
聊完缓存,再聊聊HTTPS
既然说到安全,顺便提一下HTTPS。
你可能知道HTTPS是"加密的HTTP",但它跟缓存有什么关系呢?
其实没有直接关系。但HTTPS有一个相关的安全头:
Strict-Transport-Security: max-age=31536000; includeSubDomains
这叫HSTS,简单说就是告诉浏览器:「以后别用HTTP跟我玩了,直接给我用HTTPS。」
防止一种叫"SSL剥离"的攻击——黑客在中间把HTTPS降级成HTTP,偷看你的数据。
还有哪些安全头值得关注?
| 头 | 作用 |
|---|---|
X-Frame-Options: DENY | 防止别人把你的页面嵌在iframe里(点击劫持) |
X-Content-Type-Options: nosniff | 告诉浏览器别乱猜内容类型 |
Content-Security-Policy | 限制资源加载来源,防止XSS |
Referrer-Policy | 控制 Referrer 信息泄露 |
这些安全头配置起来不麻烦,但能挡住很多常见攻击。建议都配置上。
到底该怎么用?
说了一堆原理,最后来点实用的。
不同资源,不同策略
| 资源类型 | 推荐策略 |
|---|---|
| JS / CSS / 图片 | max-age=31536000, immutable(一年,不用改) |
| HTML页面 | no-cache,每次都协商 |
| API接口 | no-cache 或 private |
| 用户敏感数据 | no-store |
核心原则
- 静态资源:狠命缓存,文件名带
hash,变了就改文件名 - HTML:别缓存,随时要最新
- API:看场景,频繁变化的要协商,不变的可以强缓存
- 敏感数据:有多远滚多远,别缓存
总结一下
这篇文章聊了浏览器缓存和刷新机制的核心概念:
- 强缓存(
Cache-Control/Expires):直接用,不过问服务器 - 协商缓存(
ETag/Last-Modified):问一下服务器能不能用 - 刷新:F5看缓存,Ctrl+F5硬刷新
- 安全:
no-store防敏感数据泄露,private防中间商缓存 - HTTPS相关:HSTS、安全响应头
理解这些机制之后,你就能解释很多奇怪的现象,也能更好地优化你的Web应用性能。