你有没有试过——自己网站点开首页,第一次加载还凑合,可第二天再打开,还是得眼巴巴等那几秒?明明是老用户,浏览器却像第一次见你似的,啥都重新拉。
其实后台早就悄悄告诉你:一半以上的访问,都是回头客。但他们没享受到任何“熟人待遇”,缓存策略压根没为他们动过脑子。
为什么默认缓存设置等于没给老用户开绿灯?
大多数网站的缓存,是按“陌生人逻辑”写的:CSS、JS、图片统一设个7天或30天过期。听起来挺久,但问题在后半程——用户第二次来,浏览器会先问服务器:“我手里的文件还能用不?”哪怕内容一模一样,只要缓存时间到了,就得发一次请求确认。
结果就是:老用户刷新页面,不是直接从本地读,而是卡在“确认环节”里干等。
真实情况是:我帮一个资讯站调缓存,他们之前把静态资源设成1天过期。后台显示六成以上是重复访问,但每次都要重拉十几个文件。后来只做了一件事:把静态资源缓存改成“永不过期”,靠版本号触发更新。回头客再打开,页面几乎是秒出。
如何通过分级缓存策略区分新老用户?
别指望一套规则通吃所有人。新用户和老用户,需求完全不同。得像分快递一样,按优先级和内容类型,一层层往下送。
第一级:浏览器缓存(所有用户都走这道门)
CSS、JS、图标这类几乎不变的文件,直接设max-age=31536000(一年)。但必须配版本号,比如 style.css?v=20240101。改了样式?换个参数就行,旧用户不受影响,新用户自动拉新版。
第二级:CDN缓存(帮新用户和异地用户省路)
首页、分类页、热门文章这些公共页面,让CDN节点缓着。设成“缓存1小时”或“有更新才失效”。这样用户点进来,CDN直接吐内容,不用一路跑到你的服务器。
第三级:服务端缓存(专供登录用户的私密通道)
购物车、订单列表、个人中心……这些页面不能公开缓存。用Redis存一份,有效期设10–30分钟。用户刷新时,数据从内存里秒取,不碰数据库。
之前接手一个电商站,登录态下的购物车每次刷新都要查6张表。加了Redis之后,老用户再点购物车,基本感觉不到加载——从“等两秒”变成“眼睛一眨就出来”。
版本号管理:改一个文件,别让所有用户都重新下载
很多人改完JS就直接覆盖原文件。结果呢?所有用户——包括昨天刚来过的老用户——全得重新下一遍。这不是优化,是惩罚。
正确姿势:改文件,就换名字,或者加哈希。比如 main.js → main.a1b2c3.js。浏览器一看文件名变了,就知道该拉新的;没变的文件(比如 lodash.min.js),继续用原来的缓存。
有个SaaS团队以前每发一版,就清空全站缓存。结果第二天老用户打开页面,比平时慢一倍。换成哈希命名后,只有真正改过的文件才会被重载,其他一切照旧。
怎么用ETag和Last-Modified避免无效请求?
ETag 和 Last-Modified 是浏览器用来“验货”的小纸条。但很多服务器乱盖章:文件内容没动,就因为保存时间变了,ETag也跟着变。用户一刷新,“纸条对不上”,浏览器只好重下整份文件。
关键在怎么盖章:ETag 应该基于文件内容生成,比如用MD5值。内容不变,ETag就不变。用户再刷,浏览器发个验证请求,服务器回个 304 Not Modified,几字节搞定,不用传文件本体。
一个老论坛曾因ETag绑了服务器IP和inode号,导致每次部署后,首页上百张图全得重载。改成内容哈希后,回头客刷页面,带宽直接松了口气。
浏览器缓存和服务端缓存冲突了怎么办?
最常踩的坑:你给页面设了浏览器缓存5分钟,服务端又用Redis缓了10分钟。表面看没问题,但一更新内容就露馅——服务端缓存清了,浏览器缓存还在,用户看到的就是旧页面。
解法就两条:
- 要么让服务端缓存时间 短于 浏览器缓存(比如浏览器设1小时,Redis设30分钟);
- 要么干脆告诉浏览器:“这个页面别瞎存,每次来都问问服务器”——用
Cache-Control: no-cache,把决策权交给服务端或CDN。
有个博客作者改完文章,读者刷半天还是旧内容。一查,浏览器缓存设了1天,Redis只缓了10分钟。改成 no-cache 后,CDN照常加速,用户也能及时看到新稿。
重复访问优化后,怎么验证效果?
别信PageSpeed那个“首屏时间”分数——它只测第一次打开。你要盯的是真实老用户的体验。
- 浏览器Network面板:勾选“Disable cache”模拟新用户,不勾选模拟回头客,直接比加载时间;
- 服务器日志:搜状态码
304的占比。如果低于三成,说明缓存大多没生效; - RUM数据:用你已经在用的监控工具(比如Cloudflare Web Analytics 或 Google Analytics 4 的Web Vitals事件),看“重复访问用户”的FCP/LCP和首次访问的差距。
之前帮一个企业站调完,重复访问的加载时间从“只快一点点”,变成“快到像开了倍速”——这种变化,用户自己就能感觉到。
今天就能执行的3个操作步骤
- 现在就打开浏览器开发者工具(F12)→ Network → 刷新页面 → 找一个CSS或JS文件 → 看Response Headers里的
Cache-Control。如果没写max-age,或者数值小于30天,立刻去你正在用的托管平台(比如Vercel、Netlify、WordPress插件或Nginx配置)加上max-age=31536000,并顺手给文件加个版本参数,比如?v=1; - 今晚上线前,检查HTML页面响应头里有没有ETag。如果没有,去你当前用的服务端框架(Next.js / Nuxt / PHP / Django等)配置一下,让它基于HTML内容生成ETag。明天用户刷新,就能收到304响应;
- 明早第一件事:登录你正在用的服务器或日志平台(比如Cloudflare Dashboard、阿里云SLS、宝塔面板),查最近24小时的访问日志,筛选状态码为
304的请求数占比。如果不到20%,说明大部分回头客还在白跑请求——那就从今天改的每个文件开始,问自己一句:这个改动,会让老用户多下一次吗?