你是不是也这样——JSON-LD 写完一测,Rich Results Test 显示“通过”,结果过两天打开 Search Console,发现增强型结果全没了?或者压根没被识别,连个面包屑都不显示。别怀疑自己,这真不是手抖漏了个逗号的事儿,是 JSON-LD 的规则藏得深、报错不直说、Google 还爱“选择性看见”。

我帮二十多个网站调过结构化数据,从本地烘焙店到出版社官网,踩过的坑比 Schema.org 的字段还多。今天不讲大道理,只给你能立刻用上的实操经验。

为什么你的 JSON-LD 总被 Google 判“无效”?

最常出问题的,是嵌套层级写反了。比如 @context 必须在最外层,但有人把它塞进 @graph 里;又比如 address 看似是个字符串,其实它必须是一个对象,且 @type 得明确设为 "PostalAddress"

举个真实例子:一家面包店用 LocalBusiness 标记店铺,把 @type 写成 ["Bakery", "Organization"]。Google 不认这种数组写法——它只接受单个字符串类型,比如 "Bakery"。多加一个 "Organization",系统直接当语法错误处理。

再比如,address 字段如果直接写 "address": "杭州市西湖区南山路1号",Google 会报“类型不匹配”。必须写成:

"address": {
  "@type": "PostalAddress",
  "streetAddress": "南山路1号",
  "addressLocality": "杭州市",
  "addressRegion": "浙江省"
}

检查方法:写完立刻去 Google 的 Rich Results Test 跑一遍。它不会告诉你“你少了个 @type”,但会标出哪一行字段被忽略——顺着那行往上翻两层,八成就是嵌套错了。

3个方法让 JSON-LD 代码既合规又易维护

方法一:用 @graph 管理多个实体,别写一堆 <script> 标签

你首页可能要同时标记 OrganizationWebSiteBreadcrumbList。如果每个都单独塞一个 <script type="application/ld+json">,页面 HTML 会越来越臃肿,后续改起来也容易漏掉某个。

正确做法是:用一个 <script> 标签,顶层用 @graph 包住所有实体。像这样:

<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@graph": [
    {
      "@type": "Organization",
      "@id": "https://yourdomain.com/#organization",
      "name": "小满烘焙"
    },
    {
      "@type": "WebSite",
      "@id": "https://yourdomain.com/#website",
      "url": "https://yourdomain.com/",
      "publisher": { "@id": "https://yourdomain.com/#organization" }
    }
  ]
}
</script>

Google 支持这种写法,而且比多个 <script> 更稳定。

方法二:给每个实体加 @id,别让 Google 猜

很多人的 JSON-LD 里没有 @id,觉得“反正内容对就行”。但 Google 不会自动猜哪个 Article 对应哪个 WebPage。如果你的文章页没给 WebPage@id,那 mainEntity 就没法准确指向它——结果就是富媒体摘要里标题有了,但作者、发布时间全丢了。

具体操作:每个实体都配一个唯一 @id,推荐直接用页面 URL 加锚点,比如:

{
  "@type": "WebPage",
  "@id": "https://yourdomain.com/article/抹茶牛角包制作指南#webpage",
  "mainEntity": { "@id": "https://yourdomain.com/article/抹茶牛角包制作指南#article" }
}

这样引用清晰,后期查问题也方便定位。

方法三:用 additionalProperty 处理自定义数据,别硬塞

Schema.org 没有 shelfLife 字段,不代表你不能标“保质期3天”。乱加字段名(比如 "shelfLife": "3天")只会被 Google 忽略。

标准解法是用 additionalProperty + PropertyValue

"additionalProperty": [{
  "@type": "PropertyValue",
  "name": "保质期",
  "value": "3天"
}]

这个组合 Google 认,也不影响其他字段解析。我们之前帮一家有机食品站用这个方式标“是否含麸质”“是否冷链配送”,上线后相关搜索点击率明显提升。

如何用 @reverse 解决“反向引用”难题

你想在作者页展示“他写过哪些文章”,但每发一篇新文,就得手动去作者页 JSON-LD 里加一条 ID?太累,也容易漏。

@reverse 就是来省这事的。你只需要在每篇文章里声明 "author": { "@id": "https://yourdomain.com/authors/张师傅" },然后在作者页的 JSON-LD 里用 @reverse 告诉 Google:“请把所有 author 指向我的页面的文章,都算作我的作品”。

作者页示例:

{
  "@context": "https://schema.org",
  "@type": "Person",
  "@id": "https://yourdomain.com/authors/张师傅",
  "@reverse": {
    "author": [
      { "@id": "https://yourdomain.com/article/抹茶牛角包制作指南" },
      { "@id": "https://yourdomain.com/article/法棍发酵全攻略" }
    ]
  }
}

注意两点:

  • @reverse 只能配合 @id 使用,不能放完整对象;
  • 目前 Google 对 @reverse 的支持还不够稳定,建议先保留传统写法(在作者页手动列文章),再叠加 @reverse 作为补充。

5个你肯定踩过的 JSON-LD 坑(附解决方案)

坑1:image 字段用相对路径
"image": "/images/logo.png",Google 不会自动补域名。它就认绝对 URL。
✅ 正确写法:"image": "https://yourdomain.com/images/logo.png"

坑2:datePublished 格式不完整
只写 "2023-01-01" 有时能过测试,但跨时区或带时间筛选的富摘要会失败。
✅ 正确写法:用 ISO 8601 完整格式,比如 "2023-01-01T09:30:00+08:00"。后端生成最稳妥。

坑3:price 字段漏了 priceCurrency
offers.price 写了 28,但没写 offers.priceCurrency,Google 默认按 USD 解析。
✅ 正确写法:加上 "priceCurrency": "CNY"(人民币用 CNY,美元用 USD,别写 RMB)。

坑4:aggregateRatingbestRatingworstRating 写反
bestRating 是满分(比如 5),worstRating 是最低分(比如 1)。写反了,星星和文字就对不上。
✅ 记住口诀:best 是顶,worst 是底。

坑5:videoObjectcontentUrlembedUrl 搞混
contentUrl 必须是 .mp4 .mov 这类可下载的视频文件地址;embedUrl 才是 YouTube 或自建播放器的 iframe 链接。
✅ 错误示范:"contentUrl": "https://www.youtube.com/embed/xxx"
✅ 正确示范:"contentUrl": "https://yourdomain.com/videos/bakery-tour.mp4"

为什么你写的 JSON-LD 在 Rich Results Test 里通过,上线后却失效?

Rich Results Test 是个“快照工具”,它只看当前页面源码里的 JSON-LD,不模拟真实爬虫行为。所以常见三种脱节:

  • JS 注入的 JSON-LD 不稳定:如果你用 document.write() 或 React useEffect 插入 JSON-LD,Googlebot 可能还没执行完 JS 就结束了抓取。
    ✅ 解法:把 JSON-LD 放进服务端模板里,或者确保它出现在 HTML 源码首屏位置(别等 JS 加载)。

  • AMP 页面有额外限制:AMP 版 JSON-LD 必须用 amp-script 兼容格式,且总大小不能超 50KB。普通写法在 AMP 里直接被忽略。
    ✅ 解法:AMP 页面单独维护一套精简版 JSON-LD,只留核心字段。

  • 新代码没被及时重抓:你改完 JSON-LD,Search Console 里还是旧状态,不是代码错了,是 Google 还没重新来过。
    ✅ 解法:用 Search Console 的 URL Inspection 工具,输入页面链接 → 点“Request indexing”,强制触发一次抓取。

真实情况:我们曾遇到一个旅游博客,JSON-LD 全部通过测试,但 Search Console 里只有 1/3 页面被识别。最后发现,它的 JSON-LD 被打包进一个叫 common.js 的文件里,靠 JS 动态插入——Googlebot 执行超时,直接跳过了。改成静态写入后,富摘要覆盖率当天就拉到了 90% 以上。

今天就能执行的 3 个优化步骤

别等“下次更新”,现在打开浏览器就能做:

  1. 打开 Search Console 的 URL Inspection 工具:粘贴你网站首页地址 → 点“Test Live URL” → 查看“Enhanced results”部分有没有报错。如果有,截图报错字段,对照上文“5个坑”逐条核对。

  2. 打开你网站的 HTML 源码(右键 → 查看网页源代码):搜 application/ld+json,找到所有 JSON-LD 块。检查每个对象是否都有 @id。没有的,统一加上,格式用 https://yourdomain.com/#organization 这样的绝对 URL + 锚点。

  3. 把你站点里超过两个 <script type="application/ld+json"> 的页面,合并成一个 @graph:复制所有 JSON-LD 内容,用中括号包成数组,放在一个 <script> 标签里。改完立刻上传,不用等发布,只要 HTML 文件更新了就行。

做完这三步,明天再进 Search Console 看“增强型结果”报告,你会发现红色警告少了一半以上。不是玄学,是这些坑,我们都替你趟过了。