seo内容必须服务端直出,首屏标题、描述、h1等不可js渲染;局部刷新需满足水合一致性、纯html响应、错误监控三原则。

关键不在“能不能局部刷新”,而在于“哪些片段能安全刷新、谁来保证内容一致”。SEO 数据更新必须由服务端主导,客户端只做接管与微调;任何依赖 JS 渲染的核心文本、结构化数据或元标签,爬虫都看不到。
首屏 SEO 内容必须直出,不可 defer 或 client-only
文章标题、摘要、<meta name="description">、Open Graph 标签、主 H1 和关键链接,全部由服务端在初始 HTML 中完整输出。不能包裹在 React.lazy、Suspense 或客户端数据请求(如 useSWR)的 fallback 里。爬虫不执行 JS,也不等 loading 结束——它只读你返回的 HTML 字符串。
- 服务端模板中用变量直接注入:例如
<title>{{ post.title }}</title> - 禁用
document.title = ...或useEffect(() => { ... })动态改标题/描述 - 若需响应式标题(如带用户昵称),服务端应根据请求上下文(如 Cookie 或 Token)预计算并写入
可刷新片段需满足“水合一致性”三要素
每个支持局部更新的区块(如评论区、相关推荐、点赞数),必须确保服务端渲染与客户端水合时的输出完全一致,否则 React 会丢弃服务端 HTML、重新创建节点,导致 SEO 内容丢失、样式闪动、事件失效。
-
稳定 key:用业务 ID(如
key={comment.id}),禁用Math.random()或数组索引 -
一致 props:服务端传的
null,客户端初始 state 也得是null(不是undefined);建议序列化后内联到window.__INITIAL_DATA__ - 隔离状态:避免用未注入初始值的全局 store(如 Zustand)驱动该区域;若必须用,服务端需提前 hydrate store
局部更新的响应必须是纯 HTML 片段,非 JSON
AJAX 成功后,前端替换的不是数据对象,而是服务端已渲染好的语义化 HTML 字符串。这样既保留 SEO 可见性,又避免客户端重复渲染逻辑。
- 后端返回
text/html响应体,内容仅限目标区域(如<div id="comments">...</div>),不含、等顶层标签 - 前端用
document.getElementById('comments').innerHTML = data或replaceWith()精准替换 - 若使用框架(如 Next.js、Remix),启用
data-fetchedpartial endpoint 并显式声明 hydration 边界
加错误边界与水合检测,防止静默降级
水合失败不会抛错,只会退化为客户端渲染——你根本不知道哪块 SEO 内容已经失效。必须主动监控。
- 为每个可刷新组件包裹
<errorboundary fallback="<div" aria-live="polite">加载失败></errorboundary> - 在组件内用
useEffect(() => { if (!document.getElementById('my-fragment')) console.warn('hydration mismatch') }, [])检查 DOM 是否匹配 - 服务端日志中标记“含可水合区块:/comments、/related-posts”,便于发布后快速验证











