GEO
返回博客
技术 AEO 实施落地

在 Next.js App Router 中注入 JSON-LD:用 Server Component 实现结构化数据

在 Next.js App Router 中,由 Server Component 直接输出 `<script type="application/ld+json">`,让结构化数据进入初始 HTML,AI 爬虫无需执行 JavaScript 即可读取。文中包含最小化 page.tsx 示例、通过 @graph 串联多个实体的方法,以及上线前使用 curl 验证的步骤。

Tenten GEO 团队发布于 2026-06-115 分钟阅读
示意图:服务器输出的结构化数据直接进入 AI 爬虫读取的初始 HTML。

在 App Router 中注入 JSON-LD,最可靠的方式是在 Server Component 里直接输出一段 `<script type="application/ld+json">`。这样,结构化数据会出现在服务器返回的初始 HTML 中,AI 爬虫无需执行 JavaScript 就能读取。至于通过 useEffect 或 Google Tag Manager 后置注入的 JSON-LD,对答案引擎而言几乎等于不存在——多数爬虫不会等页面完成 hydration,就已经抓取完毕并离开。

为什么必须由服务器端输出?

关键在于输出时机。Server Component 会在请求发生时把 JSON-LD 写进 HTML 字符串,因此 GPTBot、ClaudeBot、PerplexityBot、Google-Extended 等爬虫首次抓取到的文件就包含完整 Schema。客户端注入则必须等待浏览器下载并执行 bundle,而多数 AI 爬虫根本不会执行这一步。这里还有一个很容易误判的陷阱:Google Rich Results Test 会替你渲染 JavaScript,所以客户端注入的数据在测试工具中看起来一切正常,让人误以为已经通过验证;但答案引擎实际读取的往往是未经渲染的原始 HTML,其中根本没有 Schema。我们为客户开展技术审计时,这是最常见、也最容易被忽略的失分项。

最小可行示例:一个 page.tsx 页面

实现代码本身很短,不需要额外安装包,也不需要创建 API 路由,直接在负责渲染文章的 Server Component 中完成即可。核心只有三件事:获取数据、组装对象、输出脚本。

  1. 在 `app/blog/[slug]/page.tsx` 中(默认就是 Server Component),先通过 `await` 获取当前文章的数据。
  2. 组装一个纯 JavaScript 对象 `jsonLd`,开头写入 `"@context": "https://schema.org"` 和 `"@type": "Article"`,其余字段(headline、datePublished、author、image)则根据文章数据动态填充。
  3. 把它放在返回 JSX 的前部:`<script type="application/ld+json" dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd).replace(/</g, "\\u003c") }} />`。
  4. 不要导入任何客户端库,也不要在文件顶部添加 `"use client"`——一旦添加,它就会变成客户端组件,前面的处理也就失去意义。

用 @graph 串联多个实体

一个页面通常不只需要一种 Schema:品牌主体对应 Organization,文章对应 Article,导航路径对应 BreadcrumbList,问答区域对应 FAQPage。与其输出四个彼此独立的 script 标签,更清晰的做法是用 `@graph` 数组把它们放进同一个 JSON-LD 对象,再通过 `@id` 建立相互指向的关系。例如,让 Article 的 `publisher` 指向 Organization 的 `@id`,再让 BreadcrumbList 的最后一项指向当前页面的 `@id`。这样,答案引擎一次解析就能获得完整的实体关系图,也更不容易抓取到相互矛盾或重复的节点。

  • Organization 和 WebSite:放在 `app/layout.tsx` 中,全站共用一次即可,不要在每个页面重复声明。
  • Article 或 BlogPosting:放在文章的 `page.tsx` 中,各字段根据当前页面的数据动态填充。
  • BreadcrumbList:按照路由层级组装,尤其有助于 AI 理解网站结构。
  • FAQPage:只有页面上确实存在问答区域时才添加,而且 `acceptedAnswer` 的文本必须与页面内容一致。不要为了凑 Schema 而虚构问答。
信息图:Server Component 在初始 HTML 中输出 JSON-LD,而客户端注入的内容会被 AI 爬虫跳过。
服务器输出的 JSON-LD 会进入初始 HTML;客户端注入的内容往往等不到爬虫读取。

让 JSON-LD 易于维护

如果把 Schema 对象散落在各个页面里,三个月后往往就没人敢改。我们的做法是抽出一个 `lib/schema.ts`,并使用 `schema-dts` 类型(`import type { Article, WithContext } from "schema-dts"`)约束每个生成函数的返回值。字段名或类型不正确时,TypeScript 会在编译阶段报错。页面只需调用 `buildArticleSchema(post)`,拿到类型安全的对象后再输出。以后只改一处,就能让全站同步生效。URL 始终使用绝对路径,并统一收口到 `SITE_URL` 常量中,避免正式网站与预览域名之间的 `@id` 对不上。

常见错误与上线前验证

  • JSON-LD 中的 `url`、`image`、`datePublished` 与页面实际内容不一致——答案引擎一旦发现偏差,就会降低对整个页面的信任。
  • 使用相对路径作为 `@id` 或 `url`,切换到预览域名后就可能指向错误位置。
  • 忘记转义 `<`,或误在页面顶部添加了 `"use client"`,导致脚本变成客户端输出。
  • 上线前,先用 Google Rich Results Test 检查语法,再用 `curl` 直接抓取页面的原始 HTML,确认脚本确实包含在初始响应中,而不是只出现在浏览器 DevTools 里。这一步最关键,因为它准确模拟了 AI 爬虫实际看到的内容。
在我们审计过的网站中,大多数 JSON-LD 问题并不是 Schema 写错了,而是它只存在于客户端。服务器返回的 HTML 中没有这些数据,AI 就会把它视为不存在。Tenten GEO Technical Audit

从技术实现走向 AI 引用

把 JSON-LD 移到 Server Component,只是让内容达到“机器可读”的最低门槛。下一步还要统一实体命名、内部链接和跨页面信息,AI 才能稳定地把你的网站作为可信来源引用。如果你不确定网站的结构化数据是否已经进入爬虫看到的 HTML,可以预约一次 30 分钟的 GEO 诊断。我们会直接抓取源代码,帮你梳理缺口,而不是只看渲染后的页面。

常见问题

如何在 Next.js App Router 中添加 JSON-LD?
在 Server Component(page.tsx 或 layout.tsx)中组装 Schema 对象,通过带有 `dangerouslySetInnerHTML` 的 `<script type="application/ld+json">` 输出,并把字符串中的 `<` 转义为 `<`。这样,结构化数据就会进入初始 HTML,AI 爬虫无需执行 JavaScript 也能读取。
可以通过 next/head 或 Metadata API 添加 JSON-LD 吗?
App Router 已不再使用 next/head,而 Metadata API 也不支持输出任意 script 标签。Next.js 官方建议直接在 Server Component 的 JSX 中渲染 `<script type="application/ld+json">`。目前,这是添加 JSON-LD 最稳定、也最容易被爬虫读取的方式。
为什么不建议用 GTM 或 useEffect 注入结构化数据?
两者都在客户端执行,JSON-LD 要等浏览器完成 hydration 后才会出现。多数 AI 爬虫只抓取初始 HTML,并不会运行 JavaScript,因此看不到这些 Schema。只有改为从服务器端输出,才能确保结构化数据真正被答案引擎读取和引用。

准备好了吗

你的品牌在 AI 答案中有多高的可见度?

通过 30 分钟 GEO 诊断,了解品牌在主要 AI 引擎中的可见度缺口,以及应该优先解决的问题。

预约 30 分钟诊断