·更新于 2026年10月25日· 15 次浏览 Nuxt3Vue3SSRHydrationBUG排查工程实践
Nuxt 3 首屏闪烁排查:一次 Vue3 Hydration Mismatch 修复记录
生产环境页面先闪一下,控制台出现 hydration mismatch。本文记录从 DOM 不一致定位到数据、时间、缓存问题,并用数据序列化、条件渲染和生命周期补丁修复的过程。

作者
ZHOUYI
线上个人站上线后,我发现文章页偶尔会先显示旧骨架,再突然跳到正文,浏览器控制台报 Hydration node mismatch。这类问题通常不是样式抖动,而是服务端渲染出的 HTML 和客户端首次渲染的 DOM 不一致,Vue 在水合时发现节点对不上,只能重新渲染。
先定位:服务端 HTML 和客户端 DOM 差在哪
我先打开报错组件,再查看页面源代码,对比服务端返回的 HTML 和浏览器最终渲染结果。发现差异集中在三处:更新时间、阅读状态、以及从 Redis 缓存里取出的推荐列表。服务端拿到的数据和客户端二次请求拿到的数据不完全一样,首屏自然会闪。
修复:把首屏内容变成可复现
- 稳定数据优先用 useAsyncData 获取,并让服务端请求结果随 HTML 一起传到客户端,避免客户端首次渲染时另起一份数据。
- 时间、随机推荐、登录态等不稳定内容,不要直接参与首屏判断;可以先渲染占位,等 onMounted 后再显示。
- Redis 页面缓存要区分公共内容和个性化内容,别把用户状态缓存进公共页面;MongoDB 查询结果也应只作为接口数据源,不在前端临时拼接。
vue
<script setup>
const { data } = await useAsyncData('post', () => fetch('/api/post').then(res => res.json()))
const ready = ref(false)
onMounted(() => { ready.value = true })
</script>
<template>
<main>
<h1>{{ data?.title }}</h1>
<p v-if='ready'>{{ data?.updatedAt }}</p>
<p v-else>加载中</p>
</main>
</template>这段代码的关键不是复杂技巧,而是让首屏只渲染服务端也能确定的内容。标题来自 useAsyncData,客户端可以复用同一份数据;更新时间这类容易受时区、格式化、缓存影响的字段,等挂载后再显示,水合就不会互相打架。
踩坑与验证
- 不要只看本地 dev,生产构建后的 SSR、压缩和缓存策略会放大问题。
- 不要依赖 window、localStorage、navigator 决定首屏结构;这些只能放到挂载后。
- 如果页面有 Redis 缓存,先临时绕过缓存验证,确认是不是缓存了不该缓存的内容。
“Hydration mismatch 的本质是首屏不可复现。把服务端和客户端第一次渲染要看到的内容收敛到同一份确定数据,闪烁自然消失。”