Nuxt 3 文章详情偶尔串内容:我把 useAsyncData 的 key 和依赖重新捋了一遍
一次路由参数变了但旧文章残留的问题,表面是缓存没清,根因是 useAsyncData 的 key、依赖和页面复用策略没对齐。

作者
ZHOUYI
前几天收到反馈:从文章列表点进详情,偶尔会看到上一篇的正文。刷新后又正常了。我先以为是接口慢或骨架屏残留,打开 Network 才发现,路由参数已经变了,但页面拿到的还是旧缓存。最后定位到 useAsyncData 的 key 复用。
先定位:为什么路由变了,文章还是旧的
复现路径也很典型:从 /article/1 点进 /article/2,如果详情组件没有重建,useAsyncData 只会在第一次执行。固定 key 会让 Nuxt 认为这份数据已经取过,于是旧正文先被渲染;等新请求回来才覆盖。网络慢时,用户看到的就是串内容。
- useAsyncData 的 key 是缓存和 payload 的标识,不会自动包含 route.params。
- 如果 key 写成固定的 article-detail,不同文章会命中同一份数据。
- 页面组件被复用或开了 keep-alive 时,setup 不一定重新执行,旧请求结果就会继续挂在页面上。
我的修法:让 key、依赖、缓存都跟着 id 走
// 若页面组件会被复用,可给页面加 fullPath 作为 key;写法以官方文档为准
const route = useRoute()
const id = computed(() => String(route.params.id ?? ''))
const { data, pending, refresh } = await useAsyncData(
`article-${id.value}`,
() => $fetch(`/api/articles/${id.value}`)
)
watch(id, () => {
refresh()
})这里我做了两件事:一是 key 里带上文章 id,避免 A 文章的数据被 B 文章复用;二是把 id 放进 watch,参数变化时重新请求。若你的页面组件会被复用,最好再给页面加 fullPath 之类的 key,让不同文章重新初始化;不确定写法时以官方文档为准。
我没有直接把 key 写成 route.fullPath,因为列表页可能带 query、排序参数,fullPath 会把无关变化也带进缓存。文章详情只认 id,必要时再补 slug 校验。这样既稳定,也方便服务端渲染时生成一致的数据标识。
顺手补上的工程细节
- 后端 Node.js 查询 MongoDB 时,也统一用文章 id 做条件,避免 slug 历史变更导致查到旧文档。
- Redis 缓存改成 article:detail:{id},不再用 article:detail:current 这种含糊 key。
- 如果用了 getCachedData,别只判断时间,还要判断 cached.id 是否等于当前 id,防止旧缓存误用。
- SSR 首屏正常后,再检查 canonical 和 og:url,防止参数页或旧缓存页被搜索引擎误收录。
“这类串内容 BUG 往往不是接口返回错,而是前端缓存标识没跟业务实体绑定。把 key 当成资源 ID 的一部分来设计,很多奇怪问题会消失。”