Next.js精通SEO第三章(TDK + OG)

TDK + meta

TDK 是 TitleDescriptionKeywords 的缩写,是 SEO(搜索引擎优化)里的核心元信息,也常统称为页面的元数据

在原生 HTML 里,它们大致对应 <head> 中的 <title><meta name="description"><meta name="keywords"> 等。使用 App Router 时,Next.js 通过 export const metadatagenerateMetadata 生成上述标签,由框架写入文档头部,无需手写整段 <head>

TDK 的作用

title

title 是页面标题,通常会出现在浏览器标签页和搜索引擎结果页(SERP)上,对点击率影响最大 。建议简洁、准确,并体现当前页与站点/栏目的关系(例如与根布局的 title.template 搭配使用,见下文)。

description

description 是页面摘要,常被用作 SERP 中的描述文案(搜索引擎也可能根据内容自行改写)。应用一两句话概括页面价值,避免堆砌关键词。

keywords

keywords 用于概括页面主题。主流搜索引擎对 <meta name="keywords"> 的排序权重已很低,但规范填写仍有利于内部归类、CMS 或后续扩展;不要为 SEO 而重复、堆砌无意义词组。

书写上的小建议(实践向)

  • title :不同页面应有区分度;全站共用的后缀可通过根布局的 title.template 统一拼接。
  • description:长度适中即可(常见建议约 150 字以内作参考),重点写清「这一页解决什么问题」。
  • keywords:用数组表达多个词即可,与页面内容一致即可。

Next.js 中如何配置 TDK

我们使用 App Router ,一般在 app 目录下的根布局 layout.tsx 中导出 metadata,作为全站默认 TDK;子路由下的 layout.tsx / page.tsx 若再次导出 metadata,会对父级进行覆盖或按字段合并 (例如子页面的 title 会覆盖继承来的默认标题,具体以 Metadata 文档 为准)。

metadata静态对象,适合不依赖请求参数、不依赖异步接口数据的场景。

tsx 复制代码
// app/layout.tsx
import type { Metadata } from 'next';

export const metadata: Metadata = {
  title: '小满优选',
  description: '小满优选描述',
  keywords: ['小满优选', '优选'],
};

子路由需要单独展示时,在对应 page.tsx(或该段的 layout.tsx 中再导出一份 metadata 即可;未声明的字段会继续沿用祖先布局的配置。

根布局里还可以用 title.default + title.template,让子页面只写短标题、全站自动带上后缀,例如:

tsx 复制代码
// app/layout.tsx(节选)
export const metadata: Metadata = {
  title: {
    default: '小满优选',
    template: '%s | 小满优选',
  },
  description: '小满优选描述',
  keywords: ['小满优选', '优选'],
};

子页面写 title: '首页' 时,在支持模板合并的情况下,浏览器标题可呈现为 首页 | 小满优选(具体以当前 Next 版本行为为准)。

tsx 复制代码
// app/home/page.tsx
import type { Metadata } from 'next';

export const metadata: Metadata = {
  title: '首页',
  description: '首页描述',
  keywords: ['首页', '小满优选'],
};

export default function Page() {
  return <div>首页</div>;
}

进阶:用 generateMetadata 动态配置 TDK

当标题、描述等需要依赖 动态路由参数查询参数接口 / 数据库 时,在对应 page.tsx(或 layout.tsx)中导出异步函数 generateMetadata ,返回 Metadata 对象即可。它在服务端执行,可与页面数据使用同一套请求逻辑(注意缓存与性能,必要时配合 fetch 的缓存选项或数据层)。

参数说明
  1. 第一个参数 props
    • params :动态路由段,例如 app/posts/[id]/page.tsx 中的 id
    • searchParams :当前 URL 的查询参数,例如 ?id=123
  2. 第二个参数 parent
    • 类型为 ResolvingMetadata ,表示父级布局已解析的 metadataawait parent 后可用于拼接标题、继承 openGraph 图片等。

下面示例假定路由为 app/posts/[id]/page.tsx ,根据 id 请求文章并生成 TDK(接口仅为演示,可换成你的真实 API):

tsx 复制代码
// app/posts/[id]/page.tsx
import type { Metadata, ResolvingMetadata } from 'next';

type Props = {
  params: Promise<{ id: string }>;
};

export async function generateMetadata(
  { params }: Props,
  parent: ResolvingMetadata
): Promise<Metadata> {
  const { id } = await params;
  const resolvedParent = await parent;

  const res = await fetch(
    `https://jsonplaceholder.typicode.com/posts/${id}`
  );
  if (!res.ok) {
    return { title: '文章未找到' };
  }
  const data = await res.json();

  return {
    title: `${data.title} | ${resolvedParent.title?.absolute ?? '文章'}`,
    description: data.body.slice(0, 150),
    keywords: [data.title],
  };
}

export default async function PostPage({ params }: Props) {
  const { id } = await params;
  return <div>文章 id:{id}</div>;
}

若还需根据 searchParams (例如 ?tab=reviews)切换描述,把函数第一个参数写为 { params, searchParams } 并在需要时同样 await searchParams 即可。

其他常用 Metadata(了解即可)

除 TDK 外,Metadata 还可配置 Open GraphTwitter Cardrobots站点图标添加到主屏幕(PWA)相关 等。配置 相对路径的图片 (如 OG 图)时,建议在根 metadata 中设置 metadataBase(站点根 URL),以便 Next 正确拼出绝对地址。

tsx 复制代码
import type { Metadata } from 'next';

export const metadata: Metadata = {
  metadataBase: new URL('https://example.com'),
  title: '小满优选',
  description: '小满优选描述',
  keywords: ['小满优选', '优选'],
  openGraph: {
    title: '...',
    description: '...',
    type: 'website',
    images: ['/og.png'],
  },
  twitter: {
    card: 'summary_large_image',
    title: '...',
    description: '...',
    images: ['/og.png'],
  },
  robots: {
    index: true,
    follow: true,
  },
  icons: {
    icon: '/favicon.ico',
  },
  appleWebApp: {
    capable: true,
    title: '小满优选',
    statusBarStyle: 'black-translucent',
  },
};

Open Graph(OG)

Open Graph 是 Facebook(现 Meta)提出的一套页面元数据协议,通过 <meta property="og:*"> 描述标题、描述、封面图、类型等。当链接被分享到微信、Slack、Discord、LinkedIn 等平台时,抓取方会读取这些标签来生成卡片预览 ,因此 OG 与 SEO (点击率、品牌呈现)和 传播体验 都密切相关。

App Router 中,Next.js 通过导出 metadatagenerateMetadata 中的 openGraph 字段,自动生成对应的 OG 标签,无需手写整段 <head>。官方说明见 Metadata APIOptimizing Metadata

实例:苹果官网的 OG 标签与分享效果

下面这段是 Apple 官网 首页实际输出的部分 OG 元数据(与页面在浏览器「查看源代码」中可见的 og:* 一致;og:image 上的查询串常用于缓存版本控制,可按需更新):

html 复制代码
<meta property="og:image" content="https://www.apple.com/ac/structured-data/images/open_graph_logo.png?202604211141" />
<meta property="og:title" content="Apple" />
<meta property="og:description" content="Discover the innovative world of Apple and shop everything iPhone, iPad, Apple Watch, Mac, and Apple TV, plus explore accessories, entertainment, and expert device support." />
<meta property="og:url" content="https://www.apple.com/" />
<meta property="og:locale" content="en_US" />
<meta property="og:site_name" content="Apple" />
<meta property="og:type" content="website" />

在微信里转发该链接时,客户端会按上述字段拼出链接卡片 :左侧一般为 og:image(此处为白底灰苹果 Logo),右侧为 og:title 粗体标题,其下为 og:description 摘要(各客户端会按自己的规则截断并加省略号)。

同一组信息在 Next.js 里可写成 Metadata['openGraph'](图片用绝对 URL 时不必依赖 metadataBase):

tsx 复制代码
import type { Metadata } from 'next';

export const metadata: Metadata = {
  openGraph: {
    title: 'Apple',
    description:
      'Discover the innovative world of Apple and shop everything iPhone, iPad, Apple Watch, Mac, and Apple TV, plus explore accessories, entertainment, and expert device support.',
    url: 'https://www.apple.com/',
    siteName: 'Apple',
    locale: 'en_US',
    type: 'website',
    images: [
      {
        url: 'https://www.apple.com/ac/structured-data/images/open_graph_logo.png?202604211141',
      },
    ],
  },
};

openGraph 能配置什么

Metadata 对象里的 openGraph 还支持视频、音频、多图、文章发布时间等。常用字段归纳如下:

配置项 典型用途
title / description 卡片标题与摘要(可与页面 TDK 一致或单独优化分享文案)
url 规范链接,建议与当前页可访问 URL 一致
siteName 站点名称
images 预览图(可多图);常配宽高与 alt
videos / audio 富媒体预览(需绝对 URL)
locale 语言区域,如 en_US
type 资源类型,如 website;文章常用 article
tsx 复制代码
// app/layout.tsx 或任意 page.tsx / layout.tsx
import type { Metadata } from 'next';

export const metadata: Metadata = {
  openGraph: {
    title: 'Next.js',
    description: 'The React Framework for the Web',
    url: 'https://nextjs.org',
    siteName: 'Next.js',
    images: [
      {
        url: 'https://nextjs.org/og.png',
        width: 800,
        height: 600,
      },
      {
        url: 'https://nextjs.org/og-alt.png',
        width: 1800,
        height: 1600,
        alt: 'My custom alt',
      },
    ],
    locale: 'en_US',
    type: 'website',
  },
};

文章类页面可设置 type: 'article',并配合 publishedTimeauthors 等,框架会输出 article:* 系列属性(详见 官方 openGraph 小节)。

Open Graph 官网与 type 去哪查

如果你想确认协议原文或查 og:type 的语义,优先看 Open Graph 官方站点:

在 Next.js 项目里,openGraph.type 还受 Next 的 TypeScript 类型约束。你可以通过两种方式确认当前版本支持的值:

  • 查看 Next.js 文档中的 openGraph 字段示例与说明:generateMetadata#opengraph
  • 在编辑器里把鼠标悬停到 Metadata['openGraph']['type'](或跳转到 next 包类型定义)查看联合类型,以你项目安装的 Next 版本为准。

metadataBase 与相对路径

OG 图片等 URL 类字段 在多数场景下需要绝对地址 。根布局中设置 metadataBase 后,当前段及子路由里的相对路径会与基址拼接,避免到处写死域名:

tsx 复制代码
import type { Metadata } from 'next';

export const metadata: Metadata = {
  metadataBase: new URL('https://acme.com'),
  openGraph: {
    images: '/og-image.png',
  },
};

若某字段已是完整 https://...,则不再套用 metadataBase。未配置 metadataBase 却在 URL 类元数据里使用相对路径,构建可能报错,这一点以你当前 Next.js 版本文档为准。

动态路由:generateMetadata 与父级 images

详情页等需要按参数拉数据时,使用 generateMetadata 。第二个参数 parent 可拿到父布局已解析的 metadata,便于在子页面追加 OG 图而不是整段覆盖,例如把当前商品图插到继承来的图片列表前面:

tsx 复制代码
import type { Metadata, ResolvingMetadata } from 'next';

type Props = { params: Promise<{ id: string }> };

export async function generateMetadata(
  { params }: Props,
  parent: ResolvingMetadata
): Promise<Metadata> {
  const { id } = await params;
  const product = await fetch(`https://api.example.com/products/${id}`).then(
    (r) => r.json()
  );
  const previousImages = (await parent).openGraph?.images || [];

  return {
    title: product.title,
    openGraph: {
      images: ['/some-specific-page-image.jpg', ...previousImages],
    },
  };
}

同一数据请求在 generateMetadata 与页面 Server Component 之间会被 memoized ,避免重复打接口(见官方 generateMetadata 说明)。

基于文件的 OG 图(推荐场景)

单独维护「导出里的图片 URL」和「仓库里的真实文件」容易不同步。对 OG 图而言,更省事的做法是使用 基于文件的 Metadata ,例如在路由段放置 opengraph-image.pngopengraph-image.tsx 动态生成图,由框架生成正确 meta。详见 opengraph-image

与布局继承的关系(简要)

子路由若导出 了自己的 openGraph 对象,会与父级按官方规则做合并或覆盖 ;若子段完全不设置 openGraph,则继续沿用祖先布局的配置。具体嵌套行为以 Metadata 字段与继承 为准。

实践建议

  • 一图多用 :分享图尺寸需符合各平台建议(常见如 1200×630 等),并保持主体在安全区内,避免裁切后信息丢失。品牌站也可用苹果这种方形 Logo 图,在部分客户端里会以缩略图形式出现。
  • 与 TDK 协调openGraph.title / openGraph.description 可与 metadata.titlemetadata.description 相同,也可为分享单独写更「点击率友好」的短文案。
  • 验证:改完后用各平台提供的调试/预览工具(如部分平台提供的 URL 调试器)拉取一次,确认缓存更新后再对外发链接。

更多字段与 HTML 对照表仍以 Next.js 官网 openGraph 为准。

相关推荐
张风捷特烈3 小时前
状态管理大乱斗#03 | Provider 源码全面评析
android·前端·flutter
灵感__idea9 小时前
Hello 算法:“走一步看一步”的智慧
前端·javascript·算法
吴文周10 小时前
告别重复劳动:一套插件让 AI 替你写代码、修Bug、做测试、上生产
前端·后端·ai编程
Mh10 小时前
我决定写一个 3D 地球仪来记录下我要去的地方
前端·javascript·动效
yaoxin52112311 小时前
390. Java IO API - WatchDir 示例
java·前端·python
懒狗小前端11 小时前
做了一个 codex 的中文文档网站,做的不好可以随便喷
前端·后端
. . . . .12 小时前
ref、useRef 和 forwardRef
前端·javascript·react.js
energy_DT12 小时前
2026年海上钻井平台数字孪生平台:引领海洋能源数字化转型
前端
Eric_见嘉12 小时前
在职前端 Agent 配置分享
前端·后端·agent