动态元数据生成:让机器读懂你的页面

2 min read
Zekari
Next.jsSEO元数据开发实践

元数据决定可见性

你建了一个网站。内容很好,功能完善。但在搜索结果里,它显示为"无标题"。在社交平台分享时,没有预览图,只有一个干瘪的链接。

问题不在内容本身,而在机器看不懂你在说什么。

搜索引擎爬虫、社交平台的爬虫、AI 系统,它们都需要结构化的元数据来理解页面。标题是什么?描述是什么?这个页面有其他语言版本吗?作者是谁?

在 Next.js 中,generateMetadata 函数就是你和这些机器对话的接口。

动态生成的必要性

元数据可以写死在 HTML 里。但当你有多语言支持、动态路由、个性化内容时,写死就不够了。

一个博客有几十篇文章,每篇文章的标题、描述、作者都不同。一个国际化网站有五种语言,每种语言的元数据都要单独配置。一个电商网站有成千上万个商品页,每个商品的 OpenGraph 图片都不一样。

动态生成元数据让你在服务端根据请求参数(路由、语言、用户状态)生成对应的元数据。

export async function generateMetadata({
  params: { locale }
}: {
  params: { locale: string }
}): Promise<Metadata> {
  const localeMetadata = metadata[locale];

  return {
    title: localeMetadata.title,
    description: localeMetadata.description,
    keywords: localeMetadata.keywords,
    metadataBase: new URL('https://example.com'),
    alternates: {
      canonical: `/${locale}`,
      languages: {
        'en': '/en',
        'zh-CN': '/zh-CN',
        'ja': '/ja',
      }
    },
    openGraph: {
      title: localeMetadata.title,
      description: localeMetadata.description,
      url: `https://example.com/${locale}`,
      images: ['/og-image.jpg'],
      locale: locale,
      type: 'website',
    },
    twitter: {
      card: 'summary_large_image',
      images: ['/twitter-card.jpg'],
    },
  };
}

这段代码在每次请求时执行,根据当前语言环境生成对应的元数据。用户访问 /en,看到英文标题。访问 /zh-CN,看到中文标题。搜索引擎抓取不同路径,索引不同语言版本。

关键字段的作用

title 和 description 是最基础的。它们出现在搜索结果的标题和摘要里,也是用户决定是否点击的第一印象。

metadataBase 定义了基础 URL。当你在 openGraph.images 里写 ['/og-image.jpg'] 时,Next.js 会把它解析成 https://example.com/og-image.jpg。没有 metadataBase,相对路径无法正确解析。

alternates 告诉搜索引擎这个页面有其他语言版本。canonical 指向标准 URL,避免重复内容问题。languages 列出所有语言及其路径,让 Google 为不同地区的用户显示对应语言的版本。

openGraphtwitter 决定了社交分享时的预览效果。当有人把你的页面链接分享到 Facebook、LinkedIn、Twitter 时,平台会抓取这些元数据,生成带图片、标题、描述的预览卡片。没有这些字段,分享链接只会显示为纯文本 URL。

robots 控制搜索引擎行为。index: true 表示允许索引,follow: true 表示允许跟踪页面内的链接。如果你有后台管理页面、隐私内容、重复页面,可以设置 index: false 来避免被搜索引擎收录。

page.tsx 对应一个具体路由,比如 /blog/[slug] 对应一篇文章。每个页面可以有自己的 generateMetadata,根据动态参数生成元数据。

layout.tsx 是布局模板,可以被多个页面共享。layout 也可以有 generateMetadata,但它生成的元数据会被 page 的元数据覆盖(按照 Next.js 的元数据合并规则)。

通常的做法是:

  • 在 layout 里设置通用元数据(网站名称、默认描述、favicon)
  • 在 page 里设置特定于该页面的元数据(标题、描述、OpenGraph 图片)

GEO(生成式引擎优化)关注的是 AI 系统如何检索、理解、引用你的内容。

title 和 description 依然重要,因为 AI 的信息来源仍然依赖搜索引擎。你在 Google 上找不到,AI 也很难找到你。

但 GEO 更看重内容的结构化程度事实的清晰陈述。AI 不会欣赏修辞,它需要能直接提取的信息。元数据提供了第一层结构,但页面内容的语义标签(如 schema.org)、明确的事实陈述、权威性引用更为关键。

参考 ai-discoverability 了解 GEO 与传统 SEO 的区别。

hreflangalternates.languages 在 HTML 中对应的标签,告诉搜索引擎页面有其他语言版本。

为什么需要?

  1. 避免重复内容惩罚:如果你的英文页面和中文页面内容相似,Google 可能认为是重复内容。hreflang 明确告诉它们是同一内容的不同语言版本。
  2. 提升用户体验:Google 会根据用户的语言偏好和地理位置,在搜索结果中显示对应语言的版本。

即使有 AI 翻译,多语言仍然必要吗?

是的。原因有二:

第一,主动权在你手里。你可以精确控制每种语言的表达方式、文化适配、关键词优化。AI 翻译可能准确,但无法替代人工对市场的理解。

第二,搜索引擎和社交平台依然按语言分发内容。你的英文页面很难出现在中文用户的搜索结果里,即使 AI 能翻译它。主动提供多语言版本,意味着你在每个语言市场都有独立的存在。

robots.indexrobots.follow 控制搜索引擎爬虫的行为:

  • index: true → 允许在搜索结果中显示此页面
  • index: false → 不在搜索结果中显示,但仍可能被抓取
  • follow: true → 允许爬虫跟踪页面内的链接
  • follow: false → 不跟踪页面内的链接

对于 LLM 爬虫(如 GPTBot、ClaudeBot),情况更复杂。它们有自己的爬虫规则,部分遵守 robots.txt,但不一定遵守页面级的 robots meta 标签。

目前控制 LLM 爬取的方式:

  1. robots.txt 中禁止特定爬虫(如 User-agent: GPTBot
  2. 使用 HTTP 头 X-Robots-Tag
  3. 某些平台提供专门的 AI 爬虫控制(如 Cloudflare 的 AI 爬虫阻止功能)

当你需要 AI 生成 favicon 和 PWA 配置时,提供以下信息会更高效:

Favicon:

  • 品牌主色调(如 #3B82F6
  • 图标风格(极简/扁平/写实)
  • 是否需要多尺寸版本(16x16, 32x32, 180x180 等)

PWA 清单:

  • 应用名称(短名称和完整名称)
  • 应用描述
  • 主题颜色和背景颜色
  • 图标路径和尺寸
  • 启动 URL
  • 显示模式(standalone / fullscreen / minimal-ui)

文件位置通常是 public/favicon/public/manifest.json

元数据是承诺

元数据不只是技术配置。它是你对外界的承诺。

你在 description 里写什么,就告诉搜索引擎这个页面是关于什么的。你在 openGraph.image 里放什么图,就决定了别人分享你的链接时会看到什么。

这些信息会被复制、转发、索引、引用。它们的生命周期远远超过页面本身。

所以动态生成元数据时,不只是填写字段。而是要问:这个页面的本质是什么?我想让机器怎么理解它?我想让看到分享链接的人得到什么印象?

元数据是你和机器的对话,也是你和未来读者的第一次见面。

Related Posts

Articles you might also find interesting

用静态导出控制视口

2 min read

Next.js 中的视口配置通过静态导出模式定义页面初始状态,理解其背后的设计约束能够更好地控制用户体验边界。

Next.js视口
Read More

从底部开始:内容策略的逆向构建法

2 min read

大多数人从顶部开始,创建广泛的认知内容。但真正高效的策略是从底部开始,从那些已经准备好转化的用户开始。这是一个关于逆向思维的实践方法。

SEO内容策略
Read More

GEO 不是要替代传统 SEO。它是在 SEO 基础上的升维

2 min read

在 AI 作为新信息中介的时代,可见性的规则已经改变。不是创造好内容就够了,而是要让机器能理解、信任并引用你。

SEOAI
Read More

继承基础配置

2 min read

配置不需要重复书写。继承机制让每个层次只表达自己的差异。

TypeScript配置管理
Read More

Purikura的页面系统

3 min read

通过五层分层继承复用架构,实现零代码修改的页面生成系统。从类型定义到页面渲染,每一层专注单一职责,实现真正的数据驱动开发。

架构设计React
Read More

Google Fonts 官方集成

2 min read

Next.js 提供了 next/font 模块,让字体加载变得简单且性能优化。Google Fonts 是最直接的商用免费字体选择。

Next.js字体
Read More

让错误浮现

1 min read

Next.js 构建悬挂问题的根源不在工具,而在掩盖。严格类型检查不是负担,而是质量的守护者。

TypeScriptNext.js
Read More

next-intl localePrefix:默认语言不显示前缀

2 min read

理解 next-intl 中 localePrefix 配置的设计哲学,以及为什么默认语言不应在 URL 中显现。

Next.jsi18n
Read More

next-intl 的服务端与客户端协同机制

3 min read

理解 next-intl 如何在 Next.js App Router 中协调服务端渲染和客户端交互,以及为什么需要显式设置 locale。

Next.jsi18n
Read More

减少 Next.js 启动时的工作量

2 min read

开发服务器启动缓慢不是偶然。它在做的事太多了。

Next.js性能优化
Read More