Metadata API 可用于定义您的应用程序元数据,以改进 SEO 和网络共享性,包括:
metadata 对象generateMetadata 函数通过以上所有选项,Next.js 将自动为您的页面生成相关的 <head> 标签,您可以在浏览器的开发者工具中检查这些标签。
metadata 对象和 generateMetadata 函数的导出仅在 Server Components 中受支持。
即使路由未定义元数据,也有两个默认的 meta 标签会始终添加:
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />其他元数据字段可以使用 Metadata 对象(用于 静态元数据)或 generateMetadata 函数(用于 生成元数据)来定义。
要定义静态元数据,请从静态的 layout.js 或 page.js 文件中导出一个 Metadata 对象。例如,为博客路由添加标题和描述:
import type { Metadata } from "next";
export const metadata: Metadata = {
title: "My Blog",
description: "...",
};
export default function Layout() {}export const metadata = {
title: "My Blog",
description: "...",
};
export default function Layout() {}您可以在 generateMetadata 文档 中查看所有可用选项的完整列表。
您可以使用 generateMetadata 函数来 fetch 依赖于数据的元数据。例如,为特定的博客文章获取标题和描述:
import type { Metadata, ResolvingMetadata } from "next";
type Props = {
params: Promise<{ slug: string }>;
searchParams: Promise<{ [key: string]: string | string[] | undefined }>;
};
export async function generateMetadata(
{ params, searchParams }: Props,
parent: ResolvingMetadata
): Promise<Metadata> {
const slug = (await params).slug;
// fetch post information
const post = await fetch(`https://api.vercel.app/blog/${slug}`).then(
(res) => res.json()
);
return {
title: post.title,
description: post.description,
};
}
export default function Page({ params, searchParams }: Props) {}export async function generateMetadata({ params, searchParams }, parent) {
const slug = (await params).slug;
// fetch post information
const post = await fetch(`https://api.vercel.app/blog/${slug}`).then(
(res) => res.json()
);
return {
title: post.title,
description: post.description,
};
}
export default function Page({ params, searchParams }) {}对于动态渲染的页面,Next.js 会单独流式传输元数据,并在 generateMetadata 解析完成后将其注入 HTML,而不会阻塞 UI 渲染。
流式元数据通过允许视觉内容首先进行流式传输来提高感知性能。
流式元数据对期望元数据存在于 <head> 标签中的机器人和爬虫程序禁用(例如 Twitterbot、Slackbot、Bingbot)。这些程序通过传入请求中的 User Agent 头部进行检测。
您可以通过 Next.js 配置文件中的 htmlLimitedBots 选项来完全自定义或禁用流式元数据。
静态渲染的页面不使用流式传输,因为元数据是在构建时解析的。
了解更多关于 流式元数据 的信息。
在某些情况下,您可能需要为元数据和页面本身获取相同的数据。为了避免重复请求,您可以使用 React 的 cache 函数 来记忆返回值,只获取一次数据。例如,同时为元数据和页面获取博客文章信息:
import { cache } from "react";
import { db } from "@/app/lib/db";
// getPost will be used twice, but execute only once
export const getPost = cache(async (slug: string) => {
const res = await db.query.posts.findFirst({ where: eq(posts.slug, slug) });
return res;
});import { cache } from "react";
import { db } from "@/app/lib/db";
// getPost will be used twice, but execute only once
export const getPost = cache(async (slug) => {
const res = await db.query.posts.findFirst({ where: eq(posts.slug, slug) });
return res;
});import { getPost } from "@/app/lib/data";
export async function generateMetadata({
params,
}: {
params: { slug: string };
}) {
const post = await getPost(params.slug);
return {
title: post.title,
description: post.description,
};
}
export default async function Page({ params }: { params: { slug: string } }) {
const post = await getPost(params.slug);
return <div>{post.title}</div>;
}import { getPost } from "@/app/lib/data";
export async function generateMetadata({ params }) {
const post = await getPost(params.slug);
return {
title: post.title,
description: post.description,
};
}
export default async function Page({ params }) {
const post = await getPost(params.slug);
return <div>{post.title}</div>;
}以下特殊文件可用于元数据:
您可以使用这些文件作为静态元数据,或者您可以使用代码以编程方式生成这些文件。
Favicons 是在书签和搜索结果中代表您网站的小图标。要将 favicon 添加到您的应用程序,请创建一个 favicon.ico 文件并将其添加到 app 文件夹的根目录。
您也可以使用代码以编程方式生成 favicons。有关更多信息,请参阅 favicon 文档。
Open Graph (OG) 图像是表示您网站在社交媒体中呈现方式的图像。要将静态 OG 图像添加到您的应用程序,请在 app 文件夹的根目录中创建一个 opengraph-image.jpg 文件。

您还可以通过在文件夹结构中更深层的位置创建 opengraph-image.jpg 来为特定路由添加 OG 图像。例如,要为 /blog 路由创建专属的 OG 图像,请在 blog 文件夹内添加一个 opengraph-image.jpg 文件。

更具体的图像将优先于文件夹结构中其上方的任何 OG 图像。
也支持其他图像格式,例如
jpeg、png和gif。有关更多信息,请参阅 Open Graph 图像文档。
ImageResponse 构造函数 允许您使用 JSX 和 CSS 生成动态图像。这对于依赖于数据的 OG 图像非常有用。
例如,要为每个博客文章生成一个独特的 OG 图像,请在 blog 文件夹内添加一个 opengraph-image.tsx 文件,并从 next/og 导入 ImageResponse 构造函数:
import { ImageResponse } from "next/og";
import { getPost } from "@/app/lib/data";
// Image metadata
export const size = {
width: 1200,
height: 630,
};
export const contentType = "image/png";
// Image generation
export default async function Image({ params }: { params: { slug: string } }) {
const post = await getPost(params.slug);
return new ImageResponse(
(
// ImageResponse JSX element
<div
style={{
fontSize: 128,
background: "white",
width: "100%",
height: "100%",
display: "flex",
alignItems: "center",
justifyContent: "center",
}}
>
{post.title}
</div>
)
);
}import { ImageResponse } from "next/og";
import { getPost } from "@/app/lib/data";
// Image metadata
export const size = {
width: 1200,
height: 630,
};
export const contentType = "image/png";
// Image generation
export default async function Image({ params }) {
const post = await getPost(params.slug);
return new ImageResponse(
(
// ImageResponse JSX element
<div
style={{
fontSize: 128,
background: "white",
width: "100%",
height: "100%",
display: "flex",
alignItems: "center",
justifyContent: "center",
}}
>
{post.title}
</div>
)
);
}ImageResponse 支持常见的 CSS 属性,包括 flexbox 和绝对定位、自定义字体、文本换行、居中以及嵌套图像。 查看所有支持的 CSS 属性的完整列表。
须知:
- 示例可在 Vercel OG Playground 中获取。
ImageResponse使用@vercel/og、satori和resvg将 HTML 和 CSS 转换为 PNG。- 仅支持 flexbox 和部分 CSS 属性。高级布局(例如
display: grid)将不起作用。