2026年10月11日
/
#Next.js
Saar Twito
结构化数据对搜索引擎一直都很重要。当搜索引擎读取你的页面时,它看到的是 HTML:一个标题、一些段落、某个地方的日期、某个地方的名字。
结构化数据可以直接告诉搜索引擎这些内容分别代表什么。这篇页面是一篇文章,这是它的标题,这个人写了它,它是在这个日期发布的。
对我而言,搜索引擎优化不是最后才勾选的选项。我希望我构建的产品和网站能够被找到,并且在被找到时能被正确理解。
这就是为什么我在所有合适的地方为每个页面添加结构化数据。我认为随着 AI 系统开始从网页内容中回答问题,结构化数据的相关性只会变得更高,而不是更低。
在 Next.js 应用中,没有任何东西会自动为你写入这些数据。你需要自己添加,以页面所需的小块 JSON 形式。
在本教程中,你将学习结构化数据是什么,以及 JSON-LD 的工作原理。然后你将把它添加到 Next.js App Router 项目中:一个安全的可复用 JsonLd 组件,可用于任何数据;从页面渲染的相同内容构建的组织数据和文章数据;以及在每次构建后验证所有内容的检查。
要跟随本教程,你需要:
将 schema-dts 作为开发依赖项安装,因为它只提供类型:
npm install -D schema-dts示例使用了一个博客。在你看到 getPost() 的地方,请使用你自己的数据源:CMS、数据库或 Markdown 文件。
<script type="application/ld+json">
{ "@context": "https://schema.org", "@type": "Article", "headline": "..." }
</script>浏览器不会执行这段脚本。当类型不是JavaScript时,该标签会变成HTML标准中称为数据块(data block)的结构,"不会被用户代理处理,而是由作者脚本或其他工具处理"。
另外还有两种格式:Microdata和RDFa,它们通过为现有HTML元素添加属性来实现。Google支持这三种格式,但推荐使用JSON-LD"如果网站架构允许的话"。对于React开发者来说,JSON-LD也是更自然的选择:它是一个从数据构建的普通对象,与渲染页面的JSX分离。
这是一个博客文章的JSON-LD块示例:
{
"@context": "https://schema.org",
"@type": "BlogPosting",
"headline": "How Caching Works in Next.js",
"datePublished": "2026-09-01T09:00:00.000Z",
"author": {
"@type": "Person",
"name": "Jane Doe"
},
"publisher": {
"@type": "Organization",
"@id": "https://example.com/#organization",
"name": "Example Dev Blog"
}
}以@开头的键是JSON-LD的关键字,其余的是Schema.org属性:
接下来的代码中将用到这四个元素。
这四个术语经常被混淆,以下是它们的关系说明:
| 术语 | 定义说明 | |------------------|--------------------------------------------------------------------------| | 结构化数据 | 概念:页面的机器可读描述 | | Schema.org | 词汇表:可使用的类型和属性 | | JSON-LD | 格式:将描述写入页面的方式 | | 富结果 | Google搜索功能:结构化数据可使页面有资格显示的增强结果(如面包屑导航、产品价格和评分等) |
简而言之,你使用Schema.org词汇表通过JSON-LD格式编写结构化数据,Google可能会使用它来显示富结果。
Google表示它使用结构化数据"理解页面内容",并收集标记内容中描述的人员、书籍和公司的信息。它还使用结构化数据决定页面是否有资格显示富结果。
"有资格"是关键点。有效的JSON-LD并不能保证显示富结果,原因有四:
结构化数据对排名也没有提升作用。正如Google的John Mueller在2025年所说:“结构化数据不会让您的网站排名更好。”
关于AI搜索?Google表示:“您不需要添加任何特殊的schema.org结构化数据”来出现在其AI功能中。Bing的网页管理员指南指出结构化数据“可能有助于更清晰的上下文建立,但不能保证可见性”。OpenAI、Anthropic和Perplexity都没有记录使用结构化数据:它们的爬虫文档只涉及爬虫访问,不涉及标记。
目前AI搜索有很多炒作,其中一些是有道理的。但我的推理并不依赖于任何一家公司的承诺。
我希望我的内容对每个阅读它的系统都尽可能清晰,无论是搜索引擎还是AI工具。结构化数据是对页面的清晰准确描述,这本身就有价值,无论谁来阅读。只是不要把它当作进入AI答案的捷径。
实际应用中有多普遍?根据我开发的网站审计工具Greadme发布的《2026年网站状态报告》,在审计的387个首页中,63%包含结构化数据。其中大部分格式良好:这些网站中有91%通过验证且没有错误。
但仍有16%的网站声明使用了FAQPage类型,而Google在2023年曾将这种富结果限制在政府和健康类网站,此后已弃用该类型。有效并不等于有用。
Next.js的JSON-LD指南建议将结构化数据“作为layout.js或page.js组件中的<script>标签渲染”。您可以将该标签粘贴到每个需要的页面中。但使用小型组件更好,因为它可以将转义和类型定义集中在一个地方。
创建components/JsonLd.tsx:
import type { Graph, Thing, WithContext } from "schema-dts";
type JsonLdData = WithContext<Thing> | Graph;
export function serializeJsonLd(data: JsonLdData): string {
return JSON.stringify(data).replace(/</g, "\\u003c");
}
export function JsonLd({ data }: { data: JsonLdData }) {
return (
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: serializeJsonLd(data) }}
/>
);
}各部分的作用如下:
该组件没有"use client"指令,因此是服务器组件,标签是服务器发送的HTML的一部分。
Next.js有Script组件,一些教程用它来处理JSON-LD。不要这样做。JSON-LD指南解释说,next/script“优化了加载和执行JavaScript”,而JSON-LD是数据。
更大的问题出现在HTML中。使用默认的afterInteractive策略时,Script内容会“在客户端注入到HTML中”。我创建了一个通过Script渲染Product块的页面,并检查了next build生成的HTML。
其中没有application/ld+json标签。数据只存在于React在浏览器中读取的JavaScript有效载荷内部。
Google 仍然可以找到它,因为它会读取 JavaScript 注入到页面中的 JSON-LD。但任何只读取 HTML 的工具都看不到任何内容。普通的 <script> 标签会将数据暴露在 HTML 中,所有人都能访问。
简短来说:JSON.stringify 生成的是有效的 JSON,但不是适合放入 HTML 中的安全 JSON。浏览器不知道你的脚本包含 JSON,它会寻找 </script> 来确定标签结束位置,即使在 JSON 字符串中间遇到也会停止。
假设产品名称来自 CMS,有人将以下内容保存为名称:
Blue Mug </script><script>alert(document.cookie)</script>使用普通的 JSON.stringify 时,服务器发送的内容为:
<script type="application/ld+json">{"@context":"https://schema.org","@type":"Product","name":"Blue Mug </script><script>alert(document.cookie)</script>"}</script>浏览器会在第一个 </script> 处终止 JSON-LD 标签。然后它会发现第二个普通 <script> 标签并执行它。这是一次跨站脚本(XSS)攻击,同时你的结构化数据也变成了无效的 JSON。
我用 jsdom 测试了这个页面,jsdom 按照 HTML 标准解析 HTML。警报执行了一次,对 JSON-LD 的 JSON.parse 报错 "JSON 中未终止的字符串"。
使用转义后,相同值变为:
<script type="application/ld+json">{"@context":"https://schema.org","@type":"Product","name":"Blue Mug \u003c/script>\u003cscript>alert(document.cookie)\u003c/script>"}</script>浏览器找不到任何 </script>。\u003c 是 JSON 对 < 的转义方式,任何 JSON 解析器都会将其还原为原始字符。在相同测试中,没有任何代码执行,JSON.parse 返回了 CMS 存储的原始名称。
你不需要攻击者就能破坏页面。HTML 标准本身也列出了 <!-- 和 <script 这些在 <script> 标签内会混淆解析器的序列。
在我的测试中,包含 <!--<script> 的值会使未转义的标签吞噬页面剩余内容,之后的标题也会从 DOM 中消失。使用转义后,页面正常渲染。
这就是 Next.js 指南建议将 < 替换为 \u003c 的原因。该建议本身直到 2025 年 5 月才被加入指南,而许多教程仍然使用普通的 JSON.stringify。如果你的 JSON-LD 包含任何非手动输入的内容(如标题、描述、产品名称或评论),请务必进行转义。
我通常在发现多个地方重复做相同事情时才会创建组件。我希望将行为集中在一个地方,这样修改或修复只需进行一次,而不是在每个副本中重复。
JSON-LD 是一个很好的例子,因为转义只需一行代码且容易被遗忘。在我维护的生产代码库中,结构化数据在九个地方被渲染。
其中七个地方对 < 进行了转义,另外两个没有,其中一个是渲染所有博客文章结构化数据的组件。
没有发生任何问题。它处理的文章描述包含 <body> 和 <video> 等标签,这些标签无法结束脚本标签,且没有包含 </script 或 <!--。
但这只是运气,而非有意设计。页面是否安全取决于你打开的是哪个文件。
将所有代码块移动到一个 JsonLd 组件中彻底解决了这个问题。转义、使用普通 <script> 而非 next/script 的选择,以及类型定义现在都集中在一个地方。每个调用站点都能通过 prop type 获得类型检查,serializeJsonLd 也可以独立测试。
从描述网站整体信息的数据开始:网站背后的组织以及网站本身。Google 建议将组织数据放置在“首页或描述组织的单一页面上”,并补充说明:“你不需要在网站的每一页都包含它”。
以下示例使用了两个常量来表示网站的名称和地址。将它们放在你的配置文件中:
// lib/site.ts
export const SITE_URL = "https://example.com";
export const SITE_NAME = "Example Dev Blog";然后从首页 app/page.tsx 渲染这两种类型:
import type { Graph } from "schema-dts";
import { JsonLd } from "@/components/JsonLd";
import { SITE_NAME, SITE_URL } from "@/lib/site";
const siteJsonLd: Graph = {
"@context": "https://schema.org",
"@graph": [
{
"@type": "Organization",
"@id": `${SITE_URL}/#organization`,
name: SITE_NAME,
url: SITE_URL,
logo: `${SITE_URL}/logo.png`,
},
{
"@type": "WebSite",
"@id": `${SITE_URL}/#website`,
name: SITE_NAME,
url: SITE_URL,
publisher: { "@id": `${SITE_URL}/#organization` },
},
],
};
export default function HomePage() {
return (
<main>
<JsonLd data={siteJsonLd} />
<h1>{SITE_NAME}</h1>
{/* 首页的其余部分 */}
</main>
);
}@graph 在一个区块中包含多个共享相同 @context 的对象。这就是为什么这个对象被类型化为 Graph 而不是 WithContext<...>。
每个项目都有一个 @id,WebSite 的发布者通过该 @id 引用 Organization,而不是重复定义。在一个区块内,仅通过 @id 的引用就足够了,因为完整的定义就在旁边。
你可能会想将这个内容放在根布局中,这样它会出现在所有页面上。在 App Router 中,布局中渲染的任何内容都会成为其下所有页面的一部分。
这样做并不错误,但会将相同的区块添加到每个页面,而 Google 表示你不需要这样做。只有当数据确实描述了所有下级页面时,才应该使用布局来添加结构化数据。
文章页面是结构化数据发挥作用的地方,也是数据最容易过时的地方。防止这两个问题的规则是:从页面渲染的相同数据构建 JSON-LD,并仅标记读者可见的内容。
这是一个完整的 app/blog/[slug]/page.tsx 示例:
import Image from "next/image";
import Link from "next/link";
import { notFound } from "next/navigation";
import type { BlogPosting, BreadcrumbList, WithContext } from "schema-dts";
import { JsonLd } from "@/components/JsonLd";
import { getAllPosts, getPost } from "@/lib/posts";
import { SITE_NAME, SITE_URL } from "@/lib/site";
export async function generateStaticParams() {
const posts = await getAllPosts();
return posts.map((post) => ({ slug: post.slug }));
}
export default async function PostPage({
params,
}: {
params: Promise<{ slug: string }>;
}) {
const { slug } = await params;
const post = await getPost(slug);
if (!post) notFound();
const breadcrumbs = [
{ name: "Home", path: "/" },
{ name: "Blog", path: "/blog" },
{ name: post.title, path: `/blog/${post.slug}` },
];const articleJsonLd: WithContext<BlogPosting> = {
"@context": "https://schema.org",
"@type": "BlogPosting",
headline: post.title,
description: post.description,
image: post.image,
datePublished: post.publishedAt,
dateModified: post.updatedAt,
author: { "@type": "Person", name: post.author.name, url: post.author.url },
publisher: {
"@type": "Organization",
"@id": `${SITE_URL}/#organization`,
name: SITE_NAME,
},
};
const breadcrumbJsonLd: WithContext<BreadcrumbList> = {
"@context": "https://schema.org",
"@type": "BreadcrumbList",
itemListElement: breadcrumbs.map((crumb, index) => ({
"@type": "ListItem",
position: index + 1,
name: crumb.name,
item: new URL(crumb.path, SITE_URL).href,
})),
};
return (
<article>
<JsonLd data={articleJsonLd} />
<JsonLd data={breadcrumbJsonLd} />
<nav aria-label="Breadcrumb">
{breadcrumbs.map((crumb, index) => (
<span key={crumb.path}>
{index > 0 && " / "}
<Link href={crumb.path}>{crumb.name}</Link>
</span>
))}
</nav>
<h1>{post.title}</h1>
<p>
作者 <a href={post.author.url}>{post.author.name}</a> ·{" "}
<time dateTime={post.publishedAt}>{post.publishedAt.slice(0, 10)}</time>
</p>
<Image src={post.image} alt="" width={1200} height={675} />
<p>{post.description}</p>
</article>
);`next/image 仅加载你允许的远程图片主机,如果图片主机尚未添加到 next.config.ts 的 images.remotePatterns 中,请添加。
articleJsonLd 中的所有值都来自 post 对象,该对象也用于渲染 JSX。标题对应 <h1>,作者对应副标题,日期对应页面上的日期。
如果编辑器修改了标题,所有相关位置都会同步更新。这与硬编码的 dateModified 或复制粘贴的评分不同,后者在页面更新时保持不变。
面包屑导航也采用相同机制。一个 breadcrumbs 数组同时生成可见导航和 BreadcrumbList,确保页面上显示的路径与结构化数据完全一致。Google 要求每个项目必须包含位置和名称,除最后一个项目外所有项目必须包含 item URL,并且至少需要两个项目。
对于结构化数据,我最关注两点:首先必须正确实现,这正是下方验证部分的作用;其次必须与用户实际看到的内容完全一致。如果某条信息仅存在于 JSON-LD 而未在页面显示,就不应该包含在数据中。
Google 官方指南也持相同观点,Bing 则指出误导性标记"可能会被忽略"。从渲染数据构建 JSON-LD 是最简单的方式,无需额外思考即可遵循这一规则。
发布者信息中包含名称和 @id。首页上单独使用 @id 就足够,因为完整的 Organization 信息在同一区块中。在当前页面,由于需要单独验证每个页面,必须通过名称保持数据完整性,同时共享的 @id 仍能标识同一组织。
根据 Google 的 Article 文档,Article 没有强制要求的属性。推荐包含作者、发布日期、修改日期、标题和图片,日期需使用 ISO 8601 格式并包含时区信息。上述示例已包含所有推荐属性。
schema-dts 类型在输入时就能捕获错误。如果拼写错误属性,TypeScript 会立即阻止:
对象字面量只能指定已知属性,但 'headLine' 在类型 'BlogPostingLeaf & { "@context": "https://schema.org"; }' 中不存在。您是否想写 'headline'?他们还会捕获注解中错误的 @type 以及错误类型的值,例如将数字用作 datePublished 的值。
他们无法检测的是任何依赖于 Google 规则或页面实际内容的内容。像 "last Tuesday" 这样的日期字符串类型检查是通过的。这就是验证的作用所在。
验证发生在两个地方:服务器实际发送的 HTML,以及以搜索引擎方式读取它的工具。
首先查看实际输出,而不是源代码。构建并启动应用:
npm run build
npm start然后在另一个终端中获取页面并提取其 JSON-LD:
curl -s http://localhost:3000/blog/nextjs-caching \
| grep -o '<script type="application/ld+json">[^<]*</script>'您应该看到每个块对应一行:
<script type="application/ld+json">{"@context":"https://schema.org","@type":"BlogPosting","headline":"How Caching Works in Next.js","description":"A practical tour of the \u003cLink> prefetch, the data cache and revalidation.","image":"https://example.com/images/nextjs-caching.png","datePublished":"2026-09-01T09:00:00.000Z","dateModified":"2026-09-20T12:00:00.000Z","author":{"@type":"Person","name":"Jane Doe","url":"https://example.com/authors/jane-doe"},"publisher":{"@type":"Organization","@id":"https://example.com/#organization","name":"Example Dev Blog"}}</script>
<script type="application/ld+json">{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https://example.com/"},{"@type":"ListItem","position":2,"name":"Blog","item":"https://example.com/blog"},{"@type":"ListItem","position":3,"name":"How Caching Works in Next.js","item":"https://example.com/blog/nextjs-caching"}]}</script>描述展示了转义字符的作用。文章描述中提到了 <Link> 组件,其 < 字符会以 \u003c 的形式出现。
此检查还会捕获之前提到的 next/script 问题以及任何在 useEffect 中添加的 JSON-LD。如果数据仅在浏览器中添加,grep 将找不到内容。您也可以通过浏览器的“查看源代码”功能进行相同检查,但不能使用开发者工具的“元素”面板,因为该面板显示的是 JavaScript 执行后的页面。
您可能还会注意到,application/ld+json 在完整响应中出现的频率比标签数量更多。Next.js 会将渲染的 React 树作为 React Server Components 的负载发送两次,一次是用于页面的水合操作,您的 JSON-LD 字符串是该树的一部分。
因此,每字节的结构化数据都会发送两次。这也是为什么应仅保留需要的 JSON-LD 属性,而不是将整篇文章正文复制到其中的原因。
两种免费工具可从搜索引擎的角度检查结构化数据,每种工具回答不同的问题。
Rich Results Test 是 Google 的工具。它会显示 Google 在页面上找到的富结果类型,以及任何错误或建议。
它最适合使用 URL 进行验证。预览部署对此非常有效,Google 推荐使用 URL 输入而非代码输入“因为使用代码输入时存在 JavaScript 限制”。对于本地构建,可以将 curl 获取的 HTML 粘贴到其代码标签中进行验证。
Schema 标记验证器会将您的标记与 Schema.org 词汇表本身进行对比。Google 官方对这个工具的描述指出,它的作用是检查“标记的语法和符合 Schema.org 标准的情况”,但不会检查 Google 的富媒体结果类型。当您需要验证 Google 未用于富媒体结果的类型,或希望确认标记符合 Schema.org 标准(无论搜索引擎如何)时,都可以使用该工具。
部署完成后,Google 搜索控制台将接管验证工作。其富媒体结果报告会显示 Google 爬取的所有页面中有效项和错误信息,而 URL 检查工具则能展示 Google 对单个页面的抓取结果。Google 官方建议在开发阶段使用富媒体结果测试工具,在部署后使用富媒体结果状态报告。
结构化数据包含大量类型、属性和规则,语法或实现上很容易出错。在软件开发的其他场景中,您已经通过类型检查、运行代码检查工具和编写测试来应对这类风险,确保问题在用户看到之前就被发现。结构化数据的处理不应例外。
在线工具适合初步检查,但没有人会在每次更改后将每个 URL 粘贴到工具中。结构化数据通常会在后期悄然失效:CMS 中某个字段被重命名、重构导致属性丢失,或标题变更但 JSON-LD 未同步更新。一个在每次构建后运行的小脚本可以提前捕获这些回归问题。
该脚本会从运行中的应用获取页面并检查以下四项:
@context 是 https://schema.org。BlogPosting 的标题与页面的 <h1> 一致,作为可见内容规则的检查。创建 scripts/check-jsonld.mjs:
// 检查运行中的 Next.js 服务器上的 JSON-LD:执行 npm run build && npm start,然后运行此脚本。
const BASE_URL = process.env.BASE_URL ?? "http://localhost:3000";
// 应包含结构化数据的页面。
const PAGES = ["/", "/blog/nextjs-caching"];
// 站点为每个类型承诺的属性。
const REQUIRED = {
Organization: ["name", "url", "logo"],
WebSite: ["name", "url"],
BlogPosting: ["headline", "datePublished", "author", "image"],
BreadcrumbList: ["itemListElement"],
};
const errors = [];
function fail(page, message) {
errors.push(page + ": " + message);
}
function decodeEntities(text) {
return text
.replace(/</g, "<")
.replace(/>/g, ">")
.replace(/"/g, '"')
.replace(/'|'/g, "'")
.replace(/&/g, "&");
}
function checkBreadcrumbs(node, page) {
const items = node.itemListElement ?? [];
if (items.length < 2) {
fail(page, "BreadcrumbList 需要至少两个项目");
}
items.forEach((item, index) => {
const isLast = index === items.length - 1;
if (item.position !== index + 1 || !item.name || (!isLast && !item.item)) {
fail(page, `面包屑 ${index + 1} 需要 position、name 和 item`);
}
});
}
for (const page of PAGES) {
const html = await (await fetch(BASE_URL + page)).text();
// 因为 JsonLd 组件会转义每个 "<",所以使用正则表达式匹配是安全的。
const blocks = [
...html.matchAll(/<script type="application\/ld\+json">(.*?)<\/script>/gs),
].map((match) => match[1]);
if (blocks.length === 0) {
fail(page, "未找到 JSON-LD");
continue;
}const h1 = html.match(/<h1[^>]*>(.*?)<\/h1>/s)?.[1].replace(/<[^>]+>/g, "");
for (const block of blocks) {
let data;
try {
data = JSON.parse(block);
} catch (error) {
fail(page, `invalid JSON (${error.message})`);
continue;
}
if (data["@context"] !== "https://schema.org") {
fail(page, '@context should be "https://schema.org"');
}
for (const node of data["@graph"] ?? [data]) {
const type = node["@type"];
for (const property of REQUIRED[type] ?? []) {
if (node[property] === undefined) {
fail(page, type + ' is missing "' + property + '"');
}
}
if (type === "BreadcrumbList") checkBreadcrumbs(node, page);
if (
type === "BlogPosting" &&
node.headline !== decodeEntities(h1 ?? "")
) {
fail(page, `headline "${node.headline}" doesn't match the <h1>`);
}
}
}if (errors.length > 0) { console.error(errors.join("\n")); process.exit(1); } console.log(JSON-LD OK on ${PAGES.length} pages);
一些细节需要特别说明:
- REQUIRED 是您自己的约定,而非 Google 的。Google 并未为 Article 列出任何必填属性,因此该列表表示本网站承诺包含的内容。当您开始使用某种类型时,请将其添加到该列表中。
- 用于查找区块的正则表达式在此处之所以可靠,是因为 JsonLd 组件对每个 `<` 都进行了转义。没有值可以包含 `</script>`,因此第一个 `</script>` 总是结束区块。这种转义机制既保护了您的测试,也保护了您的用户。
- React 会对 `<h1>` 中的 `'` 和 `&` 等字符进行转义,因此在标题比较之前,decodeEntities 会将它们还原。
该脚本使用内置的 fetch,因此不需要任何依赖项。将其添加到 package.json 中:
{ "scripts": { "check:jsonld": "node scripts/check-jsonld.mjs" } }
当 npm start 正在运行时,可以在第二个终端中运行它:
npm run check:jsonld
当一切正常时,它会输出 `JSON-LD OK on 2 pages`。要查看它失败的情况,我移除了组织的标志,修改了文章的 `<h1>` 但未更改其数据,并将之前未转义的页面添加到列表中。脚本报告了所有三个错误并以代码 1 退出:
/: Organization is missing "logo" /blog/nextjs-caching: headline "How Caching Works in Next.js" doesn't match the <h1> /experiments/unescaped: invalid JSON (Unterminated string in JSON at position 68 (line 1 column 69))
在 CI 环境中,应在运行 `npm run build` 之后执行此脚本,同时让 `npm start` 在后台运行,并在服务器不在 3000 端口时设置 BASE_URL。非零退出代码会使作业失败,因此损坏的结构化数据永远不会到达生产环境。
## 结论
结构化数据以搜索引擎能够理解的形式描述您的页面。在本教程中,您将它添加到了 Next.js App Router 网站中:
- 一个渲染普通 `<script>` 并对 `<` 进行转义的 JsonLd 组件,确保没有值可以跳出标签
- 首页上的组织和网站数据,通过 @id 进行链接
- 从页面渲染的相同数据构建的文章和面包屑导航数据
- 对 HTML 中实际内容、在线验证器以及构建后验证 JSON-LD 的脚本进行检查
我认为结构化数据如今几乎已成为必需品。它也从未如此容易编写:AI 助手可以在几秒钟内为任何页面生成 JSON-LD 块。但生成的并不等同于正确的。
验证所编写的内容是否有效,是否包含 Google 要求的属性,且每个值是否与页面实际内容一致。验证工具和检查脚本的作用正是如此。
请记住,有效的结构化数据可以使页面具备获得丰富结果的资格,但不能保证一定能获得。
如果需要对实时页面进行二次验证,免费的 Google Schema 验证器可无需注册,直接检查任意 URL 是否符合 Schema.org 和 Google 丰富结果要求。
合作伙伴推荐课程
(在新标签页中打开)
广告
- Coursera 上的 GenAI for SEO:实战手册 IBM Skills Network 团队 2 周课程,每周 2 小时 初学者 证书 查看课程(在新标签页中打开)
- Udemy 上的 Google Apps Script:创建项目管理应用 项目 Laurence Svekis 4.4(满分5.0)(26人评价)3 小时 初学者 证书 查看课程(在新标签页中打开)
- Skillshare 上的 SEO Google:SEO 基础:WordPress SEO 入门 Jim Bruce 4.4(满分5.0)(26人评价)1 小时 26 分钟 初学者 查看课程(在新标签页中打开)
- Udemy 上的 Google 高级搜索:像专家一样查找资料 Samy Mkacher 3.9(满分5.0)(1,168人评价)1 小时 24 分钟 初学者 证书 查看课程(在新标签页中打开)
更多搜索引擎优化(SEO)课程请访问 Class Central
→
我是一名软件开发人员和 SEO 专家,热爱构建真正满足用户需求的产品。我喜欢将创意转化为实际产品,探索新技术,并在过程中不断学习。我也热衷于与其他开发者分享所学知识。
如果你读到了这里,请感谢作者以表达你的支持。说声谢谢
免费学习编程。freeCodeCamp 的开源课程已帮助超过 40,000 人成为开发人员。立即开始学习