07-SSR水合问题实战排查与修复记录 SSR 水合问题实战排查与修复记录2026/8/22背景项目B站风格视频平台Nuxt 3 Vue 3 Go 微服务架构在开发过程中浏览器控制台反复出现水合警告hydration mismatch warnings最初以为是 SSR 框架的问题一度想放弃 SSR 转纯 CSR。经过几轮排查发现根源非常集中修复成本很低。症状[Vue warn]: Hydration completed but contains mismatches.伴随现象页面闪烁先显示未登录再变成已登录部分交互失效按钮点击无反应控制台警告不断排查过程第一轮怀疑 SSR 本身最初认为 SSR 是问题根源考虑全面关闭 SSR 转 CSR。但查阅 B 站官方技术博客后发现B 站 2021 年重构选择的是Vue 3 SSR/CSR 混合方案首页和 Tag 页 SSR 支撑千万级流量。SSR 不是问题问题在具体实现。第二轮定位到 localStorage通过全局搜索safeStorage.getItem、window.、document.等浏览器 API发现所有水合警告的根因是同一个模式// 错误写法顶层执行SSR 时无法访问constuserJSON.parse(safeStorage.getItem(user)||{})consttokensafeStorage.getItem(token)SSR 时服务端没有localStoragesafeStorage返回null。服务端渲染出未登录状态客户端水合时发现应该是已登录两边不一致Vue 报错。第三轮统计影响范围结果出乎意料——真正有问题的只有 9 处集中在 5 个文件文件行数问题VideoPlayer.vue87, 106字幕设置读 localStorageCollectionDetailView.vue17user 对象顶层读取CollectionListView.vue13, 15user 对象顶层读取CollectionEditView.vue19user 对象顶层读取UserProfileView.vue45, 49user 对象顶层读取api/aiSummary.ts8window.location.origin 顶层引用其余所有safeStorage调用都在onMounted、事件处理函数、watch回调中这些只在客户端执行不会导致水合问题。修复方案方案选择业界有三种主流方案ClientOnly包裹— 简单但粗暴会导致 SSR 内容空白闪烁onMounted延迟读取— 常用但无法解决首屏一致性useCookie替代 localStorage— Nuxt 官方推荐SSR 原生支持最终选择方案 3因为 Cookie 是 HTTP 请求的一部分服务端和客户端都能读取。具体实现Go 后端改动在所有登录/注册/刷新 token 的接口中增加Set-Cookie响应头func(h*UserExtendHandler)setSessionCookies(w http.ResponseWriter,token,refreshTokenstring,userIDint64,nickname,avatarstring){http.SetCookie(w,http.Cookie{Name:token,Value:token,Path:/,MaxAge:86400*7,HttpOnly:false,SameSite:http.SameSiteLaxMode,})http.SetCookie(w,http.Cookie{Name:refresh_token,Value:refreshToken,Path:/,MaxAge:86400*30,HttpOnly:false,SameSite:http.SameSiteLaxMode,})userJSON,_:json.Marshal(...)http.SetCookie(w,http.Cookie{Name:user_info,Value:url.QueryEscape(string(userJSON)),Path:/,MaxAge:86400*7,HttpOnly:false,SameSite:http.SameSiteLaxMode,})}注意user_info是 JSON 字符串含双引号必须用url.QueryEscape编码后才能写入 Cookie。前端 useAuth 组合式函数exportconstuseAuth(){constcookieTokenuseCookiestring|null(token,{default:()null})constcookieUserRawuseCookiestring|null(user_info,{default:()null})constusercomputed((){if(cookieUserRaw.value){try{returnJSON.parse(decodeURIComponent(cookieUserRaw.value))}catch{returnnull}}// 客户端兜底Cookie 不存在时读 localStorage兼容旧会话if(import.meta.client)returngetStoredUser()returnnull})// ...return{token,refreshToken,user,isLoggedIn}}useCookie在 SSR 时从请求的Cookie头读取在客户端从document.cookie读取同一个值水合一致。前端 auth.ts 同步exportfunctionsetAuthSession(session){// 同时写入 localStorage兼容旧代码和 Cookie供 SSR 读取safeStorage.setItem(TOKEN_KEY,session.token)setClientCookie(token,session.token,86400*7)// ... 同样处理 refresh_token 和 user_info}遗留问题VideoPlayer.vue的字幕设置subtitleEnabled、subtitleSettings是纯客户端偏好SSR 阶段不需要参与。处理方式用默认值初始化然后在import.meta.client块中从 localStorage 读取覆盖。总结水合问题不是 SSR 的锅是代码放错位置。核心教训SSR 页面的顶层不要读浏览器 APIlocalStorage、window、documentCookie 是 SSR 安全的状态存储方案useCookie天然跨端一致问题范围比想象的小——9 处代码修复所有页面 SSR 正常

相关新闻

最新新闻

掌阅科技大数据开发岗秋招笔试复盘:核心考点与备战经验

掌阅科技大数据开发岗秋招笔试复盘:核心考点与备战经验

2023年秋招那阵子,我在投递大数据开发岗位的过程中,专门挑了掌阅科技来试水。一方面是因为掌阅作为老牌数字阅读平台,技术栈在互联网公司里属于比较主流和规范的,Java 大数据生态这套组合在秋招里复用性很高;另一方面…

2026/8/30 1:17:41
Perplexity发布便携电脑智能体:Agent端侧操控电脑的实践参考

Perplexity发布便携电脑智能体:Agent端侧操控电脑的实践参考

Perplexity 最近放出了一个值得关注的研究方向:把 AI 智能体放进便携电脑端,而不是让它继续待在云端的聊天框里。这次“Perplexity 便携电脑智能体研究发布”的核心信息是,智能体不再只是“能回答问题”,而是能接管电脑上的实际任…

2026/8/30 1:17:41
开源AI模型免费开放,开发者如何从调用者变成构建者

开源AI模型免费开放,开发者如何从调用者变成构建者

最近圈子里讨论度很高的一件事,就是黄仁勋推出了开源AI模型,并且向开发者免费开放。很多人的第一反应是“又有一个模型可以白嫖了”,第二反应是“那我是不是也应该试试”。但如果你真的把它当成一次普通的版本更新,大概率会错过真…

2026/8/30 1:17:41
谷歌微软阿里美团实习面经:四家大厂面试风格与备战全解析

谷歌微软阿里美团实习面经:四家大厂面试风格与备战全解析

刚整理完手头的实习面试记录,正好把谷歌、微软、阿里、美团这四家的实习生面经一次性写透。这四家放在一起聊特别有意思,因为它们几乎代表了国内外面试风格的四个极端:谷歌和微软偏重算法与系统设计、流程长且稳;阿里重工程落地和…

2026/8/30 1:17:41
从投递到拿offer:BAT实习面试全流程实战指南

从投递到拿offer:BAT实习面试全流程实战指南

每年到了这个时间点,总有一批学弟学妹开始疯狂刷题、背八股、找内推,就为了能挤进BAT(百度、阿里、腾讯)的实习门槛。说实话,我在校招路上摸爬滚打了这么久,也帮部门做过几次实习生面试评审,见过…

2026/8/30 1:17:41
全速域无速度传感器高频注入+SMO观测器加权切换模型研究(Simulink仿真实现)

全速域无速度传感器高频注入+SMO观测器加权切换模型研究(Simulink仿真实现)

💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 &#x1f381…

2026/8/30 1:12:41