确认缓存是否真的命中
遇到并发性能瓶颈时,我一般先确认服务端是否真的在输出缓存响应。直接压测看 QPS 没有意义,更靠谱的是在响应头里找缓存标识。如果是自部署的 Node 层,检查 x-nitro-cache 或 x-cache 头;如果前面有 CDN,看 cf-cache-status、x-cache 或 age。如果 MISS 比例持续偏高,说明路由规则没配上缓存,或者缓存键带上了动态参数。可以先拿一个静态路由单独测试,比如 curl -I https://example.com/about,观察响应头,确认有没有 swr 或 cache-control: public, max-age=...。这一步能快速排除配置没生效的可能。
容易误判的地方:开发模式与生产环境不一致
很多人配置完路由规则后本地测试发现缓存没生效,就怀疑写错了。实际上 Nuxt 3 的开发模式下默认会禁用大多数缓存行为,想要验证效果必须构建后再启动生产模式。先跑 npm run build,再用 node .output/server/index.mjs 启动服务,或者直接用 nuxt start。如果用了 routeRules 里的 swr 或 static,务必检查构建产物里的 nitro.json 或者路由配置是否被正确注入。常见坑是忘记在 nuxt.config.ts 里配置 nitro 选项,导致自定义键没有生效。
素材1原样段落:Nuxt 3 的缓存策略主要在 nuxt.config.ts 中通过 nitro 配置实现。你可以在 export default defineNuxtConfig 中设置 nitro 选项,例如 routeRules 用于定义页面级别的缓存规则。常见的配置项包括 swr、static、redirect 等,其中 swr(Stale-While-Revalidate)模式适合高并发场景,允许返回过期缓存的同时异步更新新缓存。配置时需注意区分开发与生产环境,因为缓存行为在开发模式下可能被禁用。
围绕这段再补充:开头可以先从 routeRules 入手,比如 routeRules: { '/blog/**': { swr: 3600 } },这表示博客列表页每 3600 秒过期,过期后仍可返回旧缓存同时后台刷新。但 swr 模式不是万能的——如果源站响应慢,首轮请求依然会等后端返回,所以建议结合 CDN 边缘缓存。另外,static 规则会在构建时预渲染为静态文件,适合永远不变的内容,但更新后需要重新构建。一般我建议先在低频次变更的路由上试 swr,比如帮助中心、文档页面,观察一段时间再推广。
页面层缓存先判断内容是否安全
不是所有页面都能直接套缓存。如果给用户个人中心配上 swr,那么 A 用户可能看到 B 用户的数据。什么页面适合?静态页面、博客文章、产品描述这类不依赖登录态或个性化数据的页面。如何判断?打开浏览器 DevTools,看页面渲染后的 HTML 是否包含用户特定信息,比如用户名、CSRF token。如果包含,就不能用 routeRules 整页缓存,必须改用组件级缓存。
素材2原样段落:启用页面缓存前必须确认页面内容是否可被安全缓存。静态页面、博客文章、产品描述等不依赖用户会话或个性化数据的页面适合缓存;而用户个人中心、购物车、实时表单等动态页面则需避免。判断方法是在 nuxt.config 中为特定路由配置 routeRules:若页面内容在所有用户间一致,可用 { swr: 3600 } 设置 1 小时缓存;若页面按 URL 参数变化,可结合 cacheKey 自定义键值。注意避免缓存包含 CSRF token 或 Session ID 的页面。
继续解释:如果页面按 URL 参数变化,比如 /product?id=123,可以设置 routeRules['/product'] = { swr: 300 },并把 cacheKey 参数设为 [$url, $query],这样每个 id 会独立缓存。但要注意参数数量有限,如果参数过多或包含随机数,缓存命中率会很低。另一种做法是只缓存不带参数的基础路径,然后用客户端请求动态数据。这一步需要结合业务场景权衡。
配置示例与验证方法
一个稳妥的优先顺序:先在 routeRules 里配几个静态页面,观察 1-2 天日志确认命中率,再拓展到其他页面。如果页面内容稍微有点动态,考虑设置较短的 swr 时间,比如 60 秒。下面是一个常用配置示例:
export default defineNuxtConfig({
nitro: {
routeRules: {
'/blog/**': { swr: 600 },
'/about': { static: true },
'/docs/**': { swr: 3600, cacheKey: ['$url'] }
}
}
})验证时除了看响应头,还可以在服务端日志里搜索 cache hit 或 cache miss,Nitro 默认会输出这类信息。如果用了 CDN,必须确认 CDN 的缓存策略与 Nitro 一致,比如 Cache-Control 头是否被覆盖。我习惯在构建物目录 .output 里查看 nitro.json 确认路由规则已打包进去。
缓存失效策略与常见风险
缓存配置好后最怕的就是数据更新了,用户看到的还是旧内容。需要设计失效机制。基于时间的失效最简单,设置 swr 的 maxAge 即可。但如果内容更新频率不确定,比如后台编辑了文章,就必须主动清除缓存。
素材4原样段落:缓存失效是防止数据过期的关键。Nuxt 3 支持基于时间的失效(如 SWR 中的 maxAge)和基于事件的显式失效。对于需要即时更新的内容,例如后台发布新文章,你可以在 API 响应头中添加 Cache-Control: no-cache,或在服务端通过 useStorage 手动清除指定缓存键。常见坑:未设置 maxAge 可能导致缓存永不过期;使用默认缓存时忽略 URL 参数可能导致不同用户看到相同内容。建议在缓存键中加入版本号或时间戳,并利用 Nuxt 的 hooks 在相关内容修改时触发缓存清除。
接着说明:手动清除的方法可以在 API 路由里使用 useStorage('cache').delItem('key'),但前提是知道缓存键的命名规则。Nitro 默认缓存键基于 URL 和方法,自定义时可以用 cacheKey 参数控制。更好的做法是通过 hooks 监听数据变更事件,比如在 server/api/publish.post.ts 里调用清除 /blog/** 相关缓存。如果不想写额外逻辑,可以配合 Webhook 或 CMS 的发布钩子来触发。这里有一个风险:如果缓存键设计不当,比如只用了 URL 路径,但查询参数不同,可能覆盖彼此。建议在 cacheKey 里显式包含必要参数。
回滚与后续维护
如果配置后出现数据错乱或缓存不刷新的问题,最快的回滚方式是移除 routeRules 里的对应规则并重新构建部署。注意,swr 模式下的过期数据会在过期后仍然被返回,所以如果发现错误需要立即清除,可以临时添加 cache-control: no-cache 响应头,或者重启服务。长期维护时,建议在 CI/CD 流程中自动化缓存清除,比如每次部署后主动 purge 一次 CDN。另外,定期检查日志中缓存命中率的变化,如果发现某个路由的 MISS 增多,可能是用户行为或参数发生了变化。最后,如果并发量极大,考虑在反向代理层(如 Nginx 或 CDN)也设置缓存,Nuxt 服务本身只负责兜底。这条配置不是必须的,但能有效减轻 Node 进程压力。