Next.js使用Head/getStaticProps时元数据无法被社交平台正确解析
1. 最高优先级排查:服务端初始HTML未注入动态元标签
所有社交爬虫、元标签检测工具默认不会执行页面的客户端JavaScript,只会抓取服务端直接返回的初始HTML内容。你在浏览器开发者工具的元素面板里能看到元标签,是客户端JS hydrate完成后动态注入的结果,不代表服务端返回的源码里存在这些标签。
验证方式:打开目标页面,右键选择「查看网页源代码」,在源码中搜索title、og:title等字段,如果只能找到_app.js里定义的默认标题acacia.,找不到业务页的动态标题,就确认是这个问题。
触发原因:你的actionData如果是在客户端通过useEffect等钩子异步拉取,服务端渲染阶段拿不到这部分数据,自然无法生成对应的动态元标签。
修复方案:
- Pages Router 场景下,将
actionData的获取逻辑迁移到getStaticProps(构建时生成)或getServerSideProps(每次请求服务端获取)中,将数据作为props传入页面组件,保证服务端渲染阶段就能拿到完整数据生成元标签 - App Router 场景下,使用官方提供的
generateMetadataAPI生成页面元数据,不要在客户端组件中定义元标签。
2. 元标签缺少唯一key导致重复标签,爬虫取值错误
Next.js的next/head组件依靠key属性、标签的name/property属性做重复标签去重。你当前代码里_app.js的title标签加了key="title",但自定义Meta组件里的title、description、og系列、twitter系列标签都没有配置对应的key,会导致head中同时存在默认元标签和业务页动态元标签,多数爬虫会优先读取第一个出现的标签,也就是默认的acacia.标题,忽略后面的动态标签。
修复方案:给所有元标签配置全局唯一的固定key,保证同key的标签只会保留最后渲染的那一个,修改Meta组件代码如下:
import Head from "next/head" import Script from "next/script" function Meta(props) { return ( <Head> <title key="title">{props.title}</title> <meta key="description" name="description" content={props.desc} /> <meta key="og:type" property="og:type" content="website" /> {props.canonical && <link rel="canonical" href={`${props.canonical}`} key="canonical" />} <meta key="og:title" property="og:title" content={props.title} /> <meta key="og:description" property="og:description" content={props.desc} /> <meta key="og:site_name" property="og:site_name" content="acacia" /> <meta key="og:url" property="og:url" content={`${props.canonical}`} /> <meta key="twitter:card" name="twitter:card" content="summary" /> <meta key="twitter:title" name="twitter:title" content={props.title} /> <meta key="twitter:description" name="twitter:description" content={props.desc} /> <meta key="twitter:site" name="twitter:site" content="@acacia_app" /> <meta key="twitter:creator" name="twitter:creator" content="@acacia_app" /> <link key="favicon" rel="icon" type="image/png" href="/favicon.ico" /> <link key="appleTouchIcon" rel="apple-touch-icon" href="/favicon.ico" /> {props.image ? (<meta key="og:image" property="og:image" content={`${props.image}`} />) : (<meta key="og:image" property="og:image" content="你的公网默认OG图片绝对地址" />)} {props.image && <meta key="twitter:image" name="twitter:image" content={`${props.image}`} />} {props.robot && <meta key="robots" name="robots" content={props.robot} />} {props.css && <link key="pageCss" rel="stylesheet" href={`${props.css}`}/>} {props.js && <Script key="pageJs" type="text/javascript" src={`${props.js}`} />} </Head> ) } export default Meta
3. _document.js 配置注意事项
你贴的_document.js完整代码本身没有逻辑错误,emotion服务端样式注入的配置是正确的,不会干扰元标签渲染。
注意规则:next/document暴露的Head组件仅用于放置全站通用、不需要动态替换的静态标签(比如charset、theme-color、全局字体、公共favicon、服务端注入的样式标签),不要在_document.js里写title、description这类需要按页面替换的动态标签,你当前的写法符合这个规则,不需要调整。
4. 其他校验项
- og:image、twitter:image必须使用公网可直接访问的绝对路径,不能用相对路径;图片不要配置防盗链拦截爬虫请求,尺寸推荐1200*630,单图大小不超过8MB
- 不要给元标签添加
data-nosnippet、robots: noindex这类拦截爬虫收录的属性 - 修复完成后,清空CDN缓存、Next.js构建缓存后重新部署,旧缓存会导致爬虫拿到历史版本的错误页面
- 每次验证都以「查看网页源代码」里的内容为准,开发者工具元素面板展示的是客户端执行后的DOM结果,不能作为爬虫抓取内容的判断依据。
内容的提问来源于stack exchange,提问作者Maxime Crtgn

