元标签
如何在 Nebutra-Sailor 中设置静态和动态元数据——标题模板、Open Graph、Twitter 卡片、规范 URL、robots 指令,以及页面级与 layout 级元数据的区别。
Next.js 16 中元数据的工作原理
在 Next.js App Router 中,元数据从 page.tsx 或 layout.tsx 文件导出。Next.js 将最近的 layout.tsx 中的元数据与当前 page.tsx 中的元数据合并,页面级元数据在任何共同字段上优先。
有两种导出形式:
| 形式 | 适用场景 |
|---|---|
export const metadata | 不依赖路由参数或外部数据的静态标题和描述 |
export async function generateMetadata() | 依赖路由参数、数据库查询或 CMS 内容的动态标题 |
标题模板
在根 layout 或分段 layout 中定义标题模板,使每个页面获得统一的后缀:
import type { Metadata } from "next";
export const metadata: Metadata = {
title: {
template: "%s | Nebutra",
default: "Nebutra — AI 原生 SaaS 平台",
},
description:
"使用 Nebutra 更快地构建和发布 AI 驱动的 SaaS 产品。",
};子页面只需导出 title: "定价",渲染出的 <title> 就会变成 定价 | Nebutra。
静态元数据示例
import type { Metadata } from "next";
export const metadata: Metadata = {
title: "定价",
description:
"简洁透明的定价方案。免费开始,按需升级。",
openGraph: {
title: "定价 — Nebutra",
description: "简洁透明的定价方案。",
url: "https://nebutra.com/zh/pricing",
siteName: "Nebutra",
images: [
{
url: "https://nebutra.com/og/pricing.png",
width: 1200,
height: 630,
alt: "Nebutra 定价",
},
],
locale: "zh_CN",
type: "website",
},
twitter: {
card: "summary_large_image",
title: "定价 — Nebutra",
description: "简洁透明的定价方案。",
images: ["https://nebutra.com/og/pricing.png"],
},
};使用 generateMetadata 实现动态元数据
对于在请求时获取内容的页面(如博客文章),使用 generateMetadata:
import type { Metadata } from "next";
import { getPost } from "@/lib/sanity";
import { notFound } from "next/navigation";
export async function generateMetadata({
params,
}: {
params: Promise<{ slug: string; lang: string }>;
}): Promise<Metadata> {
const { slug, lang } = await params;
const post = await getPost(slug, lang);
if (!post) return {};
return {
title: post.title,
description: post.excerpt,
openGraph: {
title: post.title,
description: post.excerpt,
type: "article",
publishedTime: post.publishedAt,
authors: [post.author.name],
images: [
{
url: post.ogImage,
width: 1200,
height: 630,
alt: post.title,
},
],
},
twitter: {
card: "summary_large_image",
title: post.title,
description: post.excerpt,
images: [post.ogImage],
},
alternates: {
canonical: `https://nebutra.com/${lang}/blog/${slug}`,
},
};
}在 Next.js 16 中,params 是一个 Promise。在读取值之前,请务必 await 它。跳过 await 会返回 undefined 并导致运行时错误。
规范 URL
在每个有明确 URL 的页面上设置 alternates.canonical。这可以防止当同一内容可通过多个路径访问时(如有无语言前缀)产生重复内容惩罚。
export const metadata: Metadata = {
alternates: {
canonical: "https://nebutra.com/zh/pricing",
languages: {
en: "https://nebutra.com/en/pricing",
zh: "https://nebutra.com/zh/pricing",
ja: "https://nebutra.com/ja/pricing",
},
},
};languages 映射为每种语言生成 <link rel="alternate" hreflang="..."> 标签,搜索引擎使用这些标签向用户提供正确的语言版本。
robots 指令
使用 robots 元数据字段按页面控制爬虫访问:
// 默认 — 索引并跟随链接
export const metadata: Metadata = {
robots: { index: true, follow: true },
};
// 阻止索引(如管理页面、草稿预览)
export const metadata: Metadata = {
robots: { index: false, follow: false, noarchive: true },
};根目录的 robots.ts 文件设置全站默认值。页面级 robots 元数据仅覆盖该页面的默认设置。
元数据字段参考
| 字段 | 类型 | 用途 |
|---|---|---|
title | string | TemplateString | 页面标题。在 layout 中使用 template,在页面中使用普通字符串。 |
description | string | 元描述。建议 120–160 个字符。 |
openGraph.title | string | OG 标题——可与 <title> 不同。 |
openGraph.description | string | OG 描述。 |
openGraph.images | OGImage[] | 包含 url、width、height、alt 的图片对象数组。 |
openGraph.type | string | 页面用 website,博客文章用 article。 |
openGraph.publishedTime | string | ISO 8601 日期。仅用于 type: "article"。 |
twitter.card | string | 有主图的文章使用 summary_large_image。 |
twitter.images | string[] | Twitter 卡片图片 URL。 |
alternates.canonical | string | 绝对规范 URL。 |
alternates.languages | Record<string, string> | i18n 页面的 hreflang 映射。 |
robots | Robots | 爬虫指令:index、follow、noarchive 等。 |
页面级 vs layout 级元数据
| 关注点 | 设置位置 |
|---|---|
| 默认标题模板 | 根 layout.tsx |
| 全站描述回退值 | 根 layout.tsx |
全站 OG siteName | 根 layout.tsx |
| 页面特定的标题和描述 | page.tsx |
| 动态 OG 图片 | page.tsx,通过 generateMetadata |
| 规范 URL | page.tsx |
| hreflang | page.tsx |
切勿在 layout 中设置 openGraph.images——layout 级 OG 图片会被该分段中的每个页面继承,导致有自己 OG 图片的页面产生错误的社交预览。
相关文档
How is this guide?
最后更新于