你重构了文章 layout、升级了 Astro / Next.js / Hugo,或者重命名了一个 frontmatter 字段。一周后 Search Console 来邮件:「Structured data issues detected——N URLs 变成 invalid」。Enhancements → Articles / FAQPage / BreadcrumbList 一片红。抽样 URL 在 Rich Results Test 失败。这种情况的根因数量很少——重命名了变量但 JSON-LD 模板还在用旧名、框架升级换了日期序列化方式、新加的 layout wrapper 把 <script type="application/ld+json"> 吞了,或者条件渲染分支漏了一批页面。不需要重写整个 schema,找到那一个坏字段就行。
15 秒判断你是哪种情况
抽样失败 URL 用 Rich Results Test 打开,逐字读错误原文(别按你的理解概括)。错误措辞直接映射到具体原因:
| Rich Results Test 报错 | 最可能的原因 |
|---|---|
Missing field "datePublished" / "author" / "image" | 重命名了 frontmatter 字段;JSON-LD 还引用旧名,结果是 undefined |
Invalid object type for field "X" | 框架升级改了值的序列化方式(Date → 字符串、数组 → 对象) |
Parsing error: ... 或 “No structured data detected” | JSON-LD block 已经不在渲染出的 HTML 里——被 wrapper / hydration / 条件分支吞掉了 |
Either "image" or "thumbnailUrl" should be specified | 图片 helper 现在返回相对路径或 null |
BreadcrumbList: itemListElement must contain at least 2 items | 面包屑生成器对部分路由返回 0 或 1 项 |
FAQPage: At least one mainEntity is required | FAQ 生成器跑在没有 Q/A 段的页面上,输出空 schema |
常见原因(按命中率排序)
1. 重命名了 frontmatter 字段,JSON-LD 还在用旧名
你把 content collection schema 里 pubDate 改成了 publishedAt。JSON-LD 模板还在读 frontmatter.pubDate,现在它是 undefined。输出长这样:
{
"@context": "https://schema.org",
"@type": "Article",
"datePublished": null
}
Google 不接受必填字段为 null / 缺失。
怎么判断:view-source 页面找 <script type="application/ld+json">,看是否有 null、缺 key 或者本应有值但是空字符串的字段。
修复:grep 代码库里 JSON-LD 生成器引用的每个字段名,逐个对照当前 frontmatter schema。简单守卫:
const datePublished = frontmatter.publishedAt ?? frontmatter.pubDate;
if (!datePublished) throw new Error(`Missing publishedAt for ${slug}`);
让构建直接失败比两周后在 Search Console 里看到错更早。
2. 框架升级改了序列化方式
Astro / Next.js minor 升级后常见坑:Date 对象原来 JSON.stringify 出 ISO 字符串,现在序列化成 {} 或本地化字符串;数组里的对象被拍扁。
怎么判断:diff 上一个能用的 commit 和当前的 view-source。看是否有字段原来是 "2026-05-19T00:00:00.000Z" 现在变成了 "5/19/2026" 或 {}。
修复:所有日期显式转 ISO 8601:
const datePublished = new Date(frontmatter.publishedAt).toISOString();
数组也显式序列化,别依赖 JSON.stringify 默认行为。
3. 新加的 layout wrapper 吞掉了 JSON-LD
你给文章包了个 <MarketingShell> 或 <ArticleFrame>。如果这个组件有自己的 <head> slot 或者过滤了 children,你的 <script type="application/ld+json"> 就到不了 document head。
怎么判断:Rich Results Test 报「No structured data detected」。view-source 整个页面:JSON-LD <script> 完全不见。模板源代码里有,但渲染时没活下来。
修复:Astro 用 <Fragment slot="head"> 或直接在 layout 的 <head> 里渲染脚本;Next.js 用 <Head> 或 App Router 的 generateMetadata / Script strategy="beforeInteractive";Hugo 确认 partial 在 head.html 里 include。
4. 条件渲染分支漏了一批页面
模板里有 {frontmatter.draft ? null : <JsonLd />} 或 {frontmatter.type === 'guide' && <JsonLd />}。重构后条件覆盖范围变了——比如老文章 type 是 undefined,全被排除。
怎么判断:Search Console Enhancements 显示「valid items」精确掉了 N 条。筛 URL 会发现它们共享一个 frontmatter 特征(老日期、缺字段、特定 category)。
修复:JSON-LD 生成器尽量无条件输出。只在真正不适用的场景返回 null(比如没 Q/A 就不输出 FAQPage)。Article / BreadcrumbList / WebSite 都应该无条件输出。
5. BreadcrumbList itemListElement 数量不对
路由重构后,面包屑生成器对某些路由只返回 1 项(Home)或返回重复项(Home > Home > Article)。Google 要求至少 2 项且 position 不重复。
{
"@context": "https://schema.org",
"@type": "BreadcrumbList",
"itemListElement": [
{ "@type": "ListItem", "position": 1, "name": "Home", "item": "https://yourdomain.com/" },
{ "@type": "ListItem", "position": 2, "name": "Troubleshooting", "item": "https://yourdomain.com/troubleshooting/" },
{ "@type": "ListItem", "position": 3, "name": "文章标题" }
]
}
注意:最后一项不能有 item URL——它代表当前页。
可直接复制的 Article + Breadcrumb 模板
{
"@context": "https://schema.org",
"@type": "Article",
"headline": "标题,控制在 110 字符以内",
"description": "一句话摘要",
"image": "https://yourdomain.com/og/article.png",
"datePublished": "2026-05-19T00:00:00.000Z",
"dateModified": "2026-05-22T00:00:00.000Z",
"author": {
"@type": "Person",
"name": "作者名",
"url": "https://yourdomain.com/about/"
},
"publisher": {
"@type": "Organization",
"name": "站点名",
"logo": {
"@type": "ImageObject",
"url": "https://yourdomain.com/logo.png"
}
},
"mainEntityOfPage": {
"@type": "WebPage",
"@id": "https://yourdomain.com/articles/article-slug/"
}
}
最短修复路径
按命中率排序:
- 逐字读 Rich Results Test 错误原文 —— 它直接告诉你坏的是哪个字段
- view-source 找 JSON-LD block,搜
null、缺 key、旧字段名 - diff 上一个能用的 commit —— 多数 regression 来自某一处具体改动
- 加构建期 JSON-LD 校验:必填字段缺失直接 fail build —— 防下一次回归
- 抽样页在 Search Console URL Inspection 重新请求索引;Enhancements 报告 1-3 周自然清理
预防建议
- CI 给每种模板一个 URL 做 Rich Results Test 快照。快照 diff 出现新错误就 fail build。
- 每次构建用 Schema.org JSON Schema 校验 JSON-LD(structured-data-testing-tool 或
schema-dts类型检查)。 - JSON-LD 模板不直接引用 frontmatter 字段——走一个强类型 helper,必填字段缺失就抛。
- 框架升级后,合并前手工跑一次 Rich Results Test,覆盖每种内容类型至少一个 URL。
- 留一个「schema canary」路由——一个包含所有支持的 schema 类型的 fixture 页面,CI 里固定校验它。
FAQ
Q:坏的 JSON-LD 会影响排名吗? A:影响 rich result 资格,不直接影响排名。蓝链结果还在,但失去星级、FAQ 折叠、面包屑显示、视频缩略图等。商品 / 食谱 / 活动这种垂类损失明显。
Q:暂时修不好,要不要把整个 JSON-LD 删掉? A:要。带病上线比不上线更坏——Google 会记录失败,长期可能降低你域名的 rich result 资格。先删,修好再上。
Q:修完了 Enhancements 还在显示 invalid,多久能清? A:Search Console Enhancements 跟着 Google 重爬刷新,预期 1-3 周。要看修没修好以 Rich Results Test 当下结果为准。
Q:Rich Results Test 显示 Valid 但 Google 不展示 rich result。 A:校验通过是必要不充分。Google 还看内容质量、新鲜度、用户信号。2026 年部分 schema 类型(FAQPage、HowTo)已被弱化或限制在特定垂类——查你的类型当前的可见性条件。
Q:一页多个 JSON-LD block 可以吗?
A:可以。一个 Article + 一个 BreadcrumbList + 一个 WebSite 是标准做法。但不要同一个 @type 重复输出多个不同值的 block,Google 可能任选一个或全部忽略。