你有没有试过清完缓存,网站反而更慢了?

别笑——真有人这么干过。
明明图片压缩了、代码拆分了、CDN也开了,可用户一刷页面还是卡顿,后台日志里全是重复请求。问题大概率不在服务器,而在你没管好的浏览器缓存:它不是没在工作,而是“太听话”地缓存了不该缓存的东西,或者“太固执”地拒绝更新该换的文件。

浏览器缓存到底在“缓存”什么?

浏览器缓存,说白了就是把网页用到的文件(比如一张Logo图、一段CSS样式、一个JS脚本)悄悄存在用户电脑里。下次打开同一页面时,它就直接从本地拿,不用再跑一趟服务器。

这些文件分两类:

  • 静态资源:Logo、图标、字体、通用CSS/JS库——内容稳定,改得少,适合多存几天;
  • 动态资源:用户头像、购物车数量、评论列表——随时可能变,缓存太久会显示旧数据。

我们帮一家本地家居电商优化时发现:他们所有按钮图标都用雪碧图(sprite),但响应头里压根没写任何缓存指令。结果每次进商品页,几十KB的图标都要重下一遍。加了一行 Cache-Control: public, max-age=31536000 后,回访用户点开详情页,明显快了一截。

强缓存与协商缓存,你该用哪把“锁”?

强缓存和协商缓存不是二选一,是分工合作:

  • 强缓存:浏览器一看 Cache-ControlExpires 还没过期,连服务器都不问,直接上本地文件。快,但风险是更新不及时。
  • 协商缓存:浏览器先问服务器一句:“我手里的 main.css 还新鲜吗?”服务器如果回个 304 Not Modified,它就安心用本地的;如果文件真变了,才下载新的。

实际怎么配?

  • 公司Logo、带哈希名的JS/CSS(比如 app.8d2e.js)——直接上强缓存,设一年;
  • 没加哈希的通用样式表(如 common.css)——用协商缓存 + 一天强缓存兜底,既防误伤,又保速度。

Cache-Control指令,你的缓存“遥控器”

Cache-Control 是现代缓存的总开关,几个常用指令得拎得清:

  • max-age=31536000:缓存一年(单位是秒);
  • public:允许浏览器和中间代理(比如公司WiFi网关)一起缓存;
  • private:只给当前用户浏览器存,别让别人看见;
  • no-cache:不是不存,是“用之前必须找服务器确认一遍”;
  • no-store:真·不存,敏感信息(如支付结果页)才用它;
  • immutable:告诉浏览器“这文件一年内绝不会变,刷新也不用验证”,省掉一次HTTP请求。

我们给一个SaaS后台配缓存时,对所有带哈希的静态资源统一加了这句:
Cache-Control: public, max-age=31536000, immutable
上线后,老用户反复切换菜单页,几乎看不到网络请求在动。

如何给不同资源制定缓存策略?

别一股脑全设成 max-age=31536000。按文件“脾气”分类处理更靠谱:

  • 永久不变的(带哈希的JS/CSS/图片):Cache-Control: public, max-age=31536000, immutable
  • 很少变的reset.cssiconfont.woff2):Cache-Control: public, max-age=86400 + ETag
  • 经常变的(首页HTML、API返回的JSON):Cache-Control: no-cachemax-age=60
  • 绝对实时的(订单支付状态页、私信列表):Cache-Control: no-store

有个细节注意:HTML文件本身尽量别设长缓存。它就像个“目录”,里面引用的JS/CSS才是重点。目录常更新,内容才稳。

更新了文件,用户却看不到怎么办?

这是最扎心的场景:你凌晨三点发版,早上客户说“怎么还是旧按钮?”
核心解法就一个:让新文件看起来是“新URL”

最佳实践是“文件指纹”——构建时自动给文件名加哈希,比如 button.jsbutton.a7f3b9.js。内容一变,哈希就变,URL就变,浏览器自然当它是新资源,重新下载。

如果你暂时没法改构建流程,退而求其次:在HTML里引用时手动加版本号,比如 <script src="app.js?v=20240520">。但得提醒运维,有些老旧CDN或代理会忽略 ?v= 后面的部分,不如指纹可靠。

实战检查:你的缓存设置生效了吗?

别猜,直接看。
打开 Chrome 或 Edge,按 F12 → 切到 Network 标签页 → 刷新页面 → 点开任意一个JS或CSS请求 → 往下拉看 Response Headers

重点盯三行:

  • Cache-Control(有没有?值对不对?)
  • ETagLast-Modified(协商缓存有没有配?)
  • Size列显示的是 memory cache 还是具体字节数(前者说明真从缓存读的)

我们曾帮一家教育平台排查,发现他们明明写了 max-age=31536000,但Network里全是 from disk cache 却加载慢。一查,是CDN配置把源站的 Cache-Control 头给覆盖掉了。最后在CDN后台补上透传规则,问题当场解决。

今天下班前就能执行的一个具体步骤

现在,打开你正在维护的那个网站(比如后台管理页、产品列表页),按 F12 打开开发者工具 → Network → 刷新页面。
在过滤栏输入 img,把所有图片请求列出来;再分别输 cssjs,把样式和脚本也筛出来。

挨个点开它们的响应头,找有没有 Cache-Control
如果看到 logo.pngvendor.7a2b.js 这类静态文件的响应头里是空的,或者写着 no-cache,那就记下它的路径(比如 /static/images/logo.png)。

然后,打开你常用的运维协作工具(比如公司用的钉钉群、飞书文档、或Jenkins构建页),发一条消息:

“麻烦帮忙给 /static//assets/ 目录下的所有 .png/.jpg/.css/.js 文件,统一加上这行响应头:Cache-Control: public, max-age=86400。测试环境先配,没问题再上生产。”

这事不用改代码,不用动构建,运维同事配个Nginx location规则或CDN缓存策略,5分钟搞定。明天你再F12看一眼,那些图片和JS的Size栏,大概率就变成 memory cache 了。