浏览器到底在偷偷帮你做什么?——HTTP缓存与刷新机制

你的浏览器可能比你想象中更"勤俭持家"。这篇文章聊聊它是怎么帮你省流量、省时间的,以及什么时候该阻止它。


你有没有注意过这样一个现象?

第一次打开一个网页,要等好几秒。第二次打开同一个网页,基本秒开。

你是不是以为浏览器記住了这个页面?它到底是怎么做到的?

今天我们来聊聊浏览器缓存------这个你天天在用,却可能从来没认真了解过的机制。


原文地址

墨渊书肆/浏览器到底在偷偷帮你做什么?------HTTP缓存与刷新机制


缓存到底是个什么东西?

想象一下这个场景。

你每天早上都去楼下的早餐店买豆浆。第一次去的时候,老板娘要问你「要甜的還是甜的」「要不要加鸡蛋」「打包还是在这吃」------问半天,你回答半天。

但如果你连着去了一个星期,每天都点「原味豆浆,不加糖,带走」。

第七天的时候,你刚走到门口,老板娘已经把豆浆打包好了递给你,连话都不用说一句。

这就是缓存。

浏览器做的就是这件事。第一次访问一个网页,它要千里迢迢去服务器「要」资源。第二次访问,它就聪明了------直接从自己的「小仓库」里拿出来给你用,省时又省力。

但问题来了:浏览器怎么知道哪些东西可以直接用?哪些东西已经过期了?

这就涉及到HTTP缓存的两个核心概念:强缓存协商缓存


强缓存:先用了再说

强缓存就像是你跟浏览器达成的一个小协议。

你告诉它:「这个资源在未来一年内都不会变,你就放心大胆地用,别来问我。」

浏览器听了这话,就直接把资源扔给你,连服务器的大门都不带敲的。

那这个"一年"的承诺是怎么实现的呢?

Expires:看时间

最早的方式是用Expires这个响应头:

http 复制代码
Expires: Wed, 21 Oct 2026 07:28:00 GMT

这就像在商品上贴了个过期日期:「2026年10月21日之前都有效。」

但这个方式有个bug:如果你的电脑时间和服务器时间不一致,比如你把电脑调快了一个月,那缓存就直接失效了------浏览器会以为已经过期了,实际上还能用。

Cache-Control:更聪明的做法

后来HTTP/1.1推出了Cache-Control,就像给缓存装了个更智能的计时器:

http 复制代码
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

http 复制代码
# 服务器返回
Last-Modified: Wed, 21 Oct 2025 07:28:00 GMT

# 浏览器下次请求
If-Modified-Since: Wed, 21 Oct 2025 07:28:00 GMT

就像你问老板:「这个文件最后改过是什么时候?如果还是那天下午,我就继续用我的版本。」

但这个方式有个缺点:精度只到秒。如果一秒内文件被修改了两次,浏览器可看不出来。

ETag:看"指纹"

后来就有了ETag,它给每个文件生成一个"指纹":

http 复制代码
# 服务器返回
ETag: "abc123"

# 浏览器下次请求
If-None-Match: "abc123"

这个指纹通常是文件的MD5哈希值,或者其他能唯一标识内容的东西。

服务器收到请求后,会比较一下ETag:如果指纹一样,说明内容没变, 返回304;如果不一样,返回200 + 新内容。

划重点:ETag的优先级高于Last-Modified。如果服务器同时给了这两个,浏览器会先用ETag。


缓存到底是怎么工作的?

让我给你串起来整个流程:

bash 复制代码
你访问一个页面
    ↓
浏览器先看强缓存(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:敏感数据别存

http 复制代码
Cache-Control: no-store

这个指令告诉浏览器:「看归看,但别存到硬盘上。」内存里用完就扔,下次重启就没了。

登录后的用户信息、token、支付相关的数据------这些都应该加上no-store

private:只存浏览器

http 复制代码
Cache-Control: private

这个的意思是:「可以缓存,但只能存在用户自己的浏览器里,别给CDN、代理那些中间商。」

用户信息存private,静态资源存public------这是基本的安全常识。


聊完缓存,再聊聊HTTPS

既然说到安全,顺便提一下HTTPS。

你可能知道HTTPS是"加密的HTTP",但它跟缓存有什么关系呢?

其实没有直接关系。但HTTPS有一个相关的安全头:

http 复制代码
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-cacheprivate
用户敏感数据 no-store

核心原则

  • 静态资源 :狠命缓存,文件名带hash,变了就改文件名
  • HTML:别缓存,随时要最新
  • API:看场景,频繁变化的要协商,不变的可以强缓存
  • 敏感数据:有多远滚多远,别缓存

总结一下

这篇文章聊了浏览器缓存和刷新机制的核心概念:

  • 强缓存Cache-Control / Expires):直接用,不过问服务器
  • 协商缓存ETag / Last-Modified):问一下服务器能不能用
  • 刷新:F5看缓存,Ctrl+F5硬刷新
  • 安全no-store防敏感数据泄露,private防中间商缓存
  • HTTPS相关:HSTS、安全响应头

理解这些机制之后,你就能解释很多奇怪的现象,也能更好地优化你的Web应用性能。

相关推荐
CodeSheep2 小时前
“渐渐能理解为何不愿意雇佣35岁以上程序猿。去年换了份工作,组里4位组员其中3位40+,发现其实最大的问题并不是说精力不济卷不动”
前端·后端·程序员
摸鱼的春哥2 小时前
【实战】吃透龙虾🦞,你写的Agent也能支持Skills渐进式披露
前端·javascript·后端
恋猫de小郭2 小时前
你还用 IDE 吗? AI 狂欢时代下 Cursor 慌了, JetBrains 等 IDE 的未来是什么?
前端·flutter·ai编程
明月_清风3 小时前
拒绝盲目 Git:VS Code 神级插件 GitLens 的 9 个进效杀手锏
前端·git
孟祥_成都3 小时前
用 AI,0 基础复刻网页顶级特效!😀
前端·javascript·vibecoding
万少9 小时前
小龙虾(openclaw),轻松玩转自动发帖
前端·人工智能·后端
Jagger_11 小时前
抱怨到躺床关灯的一次 DIY 记录
前端
陈随易14 小时前
前端大咖mizchi不满Rust、TypeScript却爱上MoonBit
前端·后端·程序员
whinc15 小时前
🚀 两年小程序开发,我把踩过的坑做成了开源 Skills
前端·微信小程序·ai编程