Skip to main content

Metadata

Next.js 有一个 Metadata API,可用于定义您的应用程序 metadata (例如 HTMLhead素内的metalink标签),以提高 SEO 和网页共享性。

有两种方法可以将 metadata 添加到您的应用程序中:

通过这两种选项,Next.js 将自动为您的页面生成相关的<head>元素。您还可以使用ImageResponse构造函数创建动态 OG 图像。

静态 Metadata

要定义静态 metadata,请从layout.js或静态page.js文件中导出一个Metadata对象

import type { Metadata } from "next";

export const metadata: Metadata = {
title: "...",
description: "...",
};

export default function Page() {}
export const metadata = {
title: "...",
description: "...",
};

export default function Page() {}

有关所有可用选项,请参阅API Reference

动态 Metadata

您可以使用generateMetadata函数来获取需要动态值的 metadata。

import type { Metadata, ResolvingMetadata } from "next";

type Props = {
params: { id: string };
searchParams: { [key: string]: string | string[] | undefined };
};

export async function generateMetadata(
{ params, searchParams }: Props,
parent: ResolvingMetadata
): Promise<Metadata> {
// read route params
const id = params.id;

// fetch data
const product = await fetch(`https://.../${id}`).then((res) => res.json());

// optionally access and extend (rather than replace) parent metadata
const previousImages = (await parent).openGraph?.images || [];

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

export default function Page({ params, searchParams }: Props) {}
export async function generateMetadata({ params, searchParams }, parent) {
// read route params
const id = params.id;

// fetch data
const product = await fetch(`https://.../${id}`).then((res) => res.json());

// optionally access and extend (rather than replace) parent metadata
const previousImages = (await parent).openGraph?.images || [];

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

export default function Page({ params, searchParams }) {}

有关所有可用参数,请参阅API Reference.

您需要知道:

  • 通过使用`generateMetadata 的静态和动态 metadata仅在服务器组件中受支持。.
  • fetch请求会自动为generateMetadatagenerateStaticParams、Layouts、Pages 和服务器组件中的相同数据进行缓存。如果fetch不可用,可以使用React cache
  • Next.js 将等待 generateMetadata 内的数据获取完成后再将 UI 流式传输到客户端。这保证了流式响应的第一部分包含<head>标签。

基于文件的 metadata

这些特殊文件可用于 metadata:

您可以将这些用于静态 metadata,或者可以通过代码以编程方式生成这些文件。

有关实现和示例,请参阅 Metadata 文件 API 参考和动态图像生成.

行为

基于文件的元数据具有更高的优先级,并将覆盖任何基于配置的元数据。

默认字段

即使路由未定义 metadata,也始终会添加两个默认的 meta标签:

<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />

您需要知道: 您可以重写默认的viewport meta 标签。

排序

Metadata 按顺序评估,从根段开始到最接近最终page.js段的段。例如:

  1. app/layout.tsx (根 Layout)
  2. app/blog/layout.tsx (嵌套的 Blog Layout)
  3. app/blog/[slug]/page.tsx (Blog Page)

合并

按照评估顺序, 从同一路由中的多个段导出的 Metadata 对象将浅层合并在一起,形成路由的最终 metadata。重复的 keys 将根据其顺序被替换

这意味着在较早段中定义的具有嵌套字段的 metadata(例如openGraphrobots将被最后一个段覆盖以定义它们。

重写字段

export const metadata = {
title: "Acme",
openGraph: {
title: "Acme",
description: "Acme is a...",
},
};
export const metadata = {
title: "Blog",
openGraph: {
title: "Blog",
},
};

// Output:
// <title>Blog</title>
// <meta property="og:title" content="Blog" />

在上面的示例中:

  • app/layout.js中的titleapp/blog/page.js中的title替换
  • app/layout.js中的所有openGraph字段在app/blog/page.js中被替换,因为app/blog/page.js 设置了openGraphmetadata。注意openGraph.description的缺失。

如果您希望在段之间共享一些嵌套字段,同时覆盖其他字段,您可以将它们提取到一个单独的变量中:

export const openGraphImage = { images: ["http://..."] };
import { openGraphImage } from "./shared-metadata";

export const metadata = {
openGraph: {
...openGraphImage,
title: "Home",
},
};
import { openGraphImage } from "../shared-metadata";

export const metadata = {
openGraph: {
...openGraphImage,
title: "About",
},
};

在上面的示例中,OG 图像在app/layout.jsapp/about/page.js之间共享,而标题是不同的。

Inheriting fields

export const metadata = {
title: "Acme",
openGraph: {
title: "Acme",
description: "Acme is a...",
},
};
export const metadata = {
title: "About",
};

// Output:
// <title>About</title>
// <meta property="og:title" content="Acme" />
// <meta property="og:description" content="Acme is a..." />

说明

  • app/layout.js中的titleapp/about/page.js中的title替换
  • app/layout.js中的所有openGraph字段都被app/about/page.js继承,因为app/about/page.js未设置openGraphmetadata。

动态图像生成

ImageResponse构造函数允许您使用 JSX 和 CSS 生成动态图像。这对于创建社交媒体图像(例如 Open Graph 图像、Twitter 卡片等)非常有用。

要使用它,您可以从next/og中导入ImageResponse:

import { ImageResponse } from "next/og";

export async function GET() {
return new ImageResponse(
(
<div
style={{
fontSize: 128,
background: "white",
width: "100%",
height: "100%",
display: "flex",
textAlign: "center",
alignItems: "center",
justifyContent: "center",
}}
>
Hello world!
</div>
),
{
width: 1200,
height: 600,
}
);
}

ImageResponse与其他 Next.js APIs(包括[路由处理程序](/docs/content/app/building-your-application/routing/route-handlers 和基于文件的 Metadata)集成良好。例如,您可以在opengraph-image.tsx文件中使用ImageResponse在构建时或在请求时动态生成 Open Graph 图像。

ImageResponse支持常见的 CSS 属性,包括 flexbox 和绝对定位、自定义字体、文本换行、居中和嵌套图像。查看支持的 CSS 属性的完整列表

您需要知道:

  • 示例可在[Vercel OG Playground]中找到。(https://og-playground.vercel.app/).
  • ImageResponse使用 @vercel/ogSatori和 Resvg 将 HTML 和 CSS 转换为 PNG。
  • 仅支持 Edge Runtime。默认的 Node.js 运行时将不起作用。
  • 仅支持 flexbox 和部分 CSS 属性。高级布局(例如display: grid)将不起作用。
  • 最大打包大小为 500KB。打包大小包括您的 JSX、CSS、字体、图像和任何其他资源。如果超过限制,请考虑减少任何资产的大小或在运行时获取。
  • 仅支持ttfotfwoff字体格式。为了最大化字体解析速度,建议优先使用ttfotf而不是woff

JSON-LD

JSON-LD是一种结构化数据格式,搜索引擎可以使用它来理解您的内容。例如,JSON-LD 是一种结构化数据格式,搜索引擎可以使用它来理解您的内容。例如,您可以使用它来描述一个人、一个事件、一个组织、一部电影、一本书、一份食谱以及许多其他类型的实体。

我们目前对 JSON-LD 的推荐是将结构化数据渲染为 <script>标签,放在您的 layout.jspage.js组件中。例如:

export default async function Page({ params }) {
const product = await getProduct(params.id);

const jsonLd = {
"@context": "https://schema.org",
"@type": "Product",
name: product.name,
image: product.image,
description: product.description,
};

return (
<section>
{/* Add JSON-LD to your page */}
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }}
/>
{/* ... */}
</section>
);
}
export default async function Page({ params }) {
const product = await getProduct(params.id);

const jsonLd = {
"@context": "https://schema.org",
"@type": "Product",
name: product.name,
image: product.image,
description: product.description,
};

return (
<section>
{/* Add JSON-LD to your page */}
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }}
/>
{/* ... */}
</section>
);
}

您可以使用Rich Results Test(适用于 Google)或通用的Schema Markup Validator验证和测试您的结构化数据。

您可以使用社区包(如schema-dts) 和 TypeScript 编写您的 JSON-LD。

import { Product, WithContext } from "schema-dts";

const jsonLd: WithContext<Product> = {
"@context": "https://schema.org",
"@type": "Product",
name: "Next.js Sticker",
image: "https://nextjs.org/imgs/sticker.png",
description: "Dynamic at the speed of static.",
};