·更新于 2026年10月25日· 10 次浏览 NuxtVue3BUG解决工程实践SEO

Nuxt 3 文章详情偶尔串内容:我把 useAsyncData 的 key 和依赖重新捋了一遍

一次路由参数变了但旧文章残留的问题,表面是缓存没清,根因是 useAsyncData 的 key、依赖和页面复用策略没对齐。

Nuxt 3 文章详情偶尔串内容:我把 useAsyncData 的 key 和依赖重新捋了一遍 封面
ZHOUYI

作者

ZHOUYI

前几天收到反馈:从文章列表点进详情,偶尔会看到上一篇的正文。刷新后又正常了。我先以为是接口慢或骨架屏残留,打开 Network 才发现,路由参数已经变了,但页面拿到的还是旧缓存。最后定位到 useAsyncData 的 key 复用。

先定位:为什么路由变了,文章还是旧的

复现路径也很典型:从 /article/1 点进 /article/2,如果详情组件没有重建,useAsyncData 只会在第一次执行。固定 key 会让 Nuxt 认为这份数据已经取过,于是旧正文先被渲染;等新请求回来才覆盖。网络慢时,用户看到的就是串内容。

  • useAsyncData 的 key 是缓存和 payload 的标识,不会自动包含 route.params。
  • 如果 key 写成固定的 article-detail,不同文章会命中同一份数据。
  • 页面组件被复用或开了 keep-alive 时,setup 不一定重新执行,旧请求结果就会继续挂在页面上。

我的修法:让 key、依赖、缓存都跟着 id 走

ts
// 若页面组件会被复用,可给页面加 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 的一部分来设计,很多奇怪问题会消失。”

Guestbook

留言

若这篇文章也曾停在你心上,留一行字吧,我会看的。

先确认一下邮箱

多这一步,是为了少些机器骚扰,也让我能更踏实地读每一条真人写下的字。验证码 10 分钟内有效;同一邮箱 60 秒内只能发一封。

本文留言

共 0 条已加载 0 条

这里还静悄悄的——愿意做第一个留下脚印的人吗?