跳到主要内容

元数据和 OG 图片

元数据 API 可用于定义应用程序元数据以改善 SEO 和网页可分享性,包括:

  1. 静态 metadata 对象
  2. 动态 generateMetadata 函数
  3. 特殊的文件约定,可用于添加静态或动态生成的faviconOG 图片

使用上述所有选项,Next.js 将自动为你的页面生成相关的 <head> 标签,可以在浏览器的开发者工具中检查。

默认字段

有两个默认的 meta 标签,即使路由没有定义元数据,也会始终添加:

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

其他元数据字段可以使用 Metadata 对象(用于静态元数据)或 generateMetadata 函数(用于生成的元数据)来定义。

静态元数据

要定义静态元数据,从静态 layout.jspage.js 文件导出 Metadata 对象。例如,要向博客路由添加标题和描述:

app/blog/layout.tsx
import type { Metadata } from 'next'

export const metadata: Metadata = {
title: 'My Blog',
description: '...',
}

export default function Page() {}

你可以在 generateMetadata 文档中查看可用选项的完整列表。

生成的元数据

你可以使用 generateMetadata 函数来 fetch 依赖于数据的元数据。例如,要获取特定博客文章的标题和描述:

app/blog/[slug]/page.tsx
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

// 获取文章信息
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) {}

流式元数据

对于动态渲染的页面,如果解析 generateMetadata 可能会阻塞渲染,Next.js 会单独流式传输解析的元数据,并在准备好后立即将其注入到 HTML 中。

静态渲染的页面不使用此行为,因为元数据在构建时解析。

了解更多关于流式元数据

缓存数据请求

在某些情况下,你可能需要为元数据和页面本身获取相同的数据。为了避免重复请求,你可以使用 React 的 cache 函数来记忆化返回值,只获取一次数据。例如,要获取博客文章信息用于元数据和页面:

app/lib/data.ts
import { cache } from 'react'
import { db } from '@/app/lib/db'

// getPost 将被使用两次,但只执行一次
export const getPost = cache(async (slug: string) => {
const res = await db.query.posts.findFirst({ where: eq(posts.slug, slug) })
return res
})
app/blog/[slug]/page.tsx
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>
}

基于文件的元数据

以下特殊文件可用于元数据:

你可以将这些用于静态元数据,或者可以使用代码以编程方式生成这些文件。

Favicon

Favicon 是在书签和搜索结果中代表你的网站的小图标。要向应用程序添加 favicon,创建一个 favicon.ico 并添加到 app 文件夹的根目录。

App 文件夹内的 Favicon 特殊文件,带有兄弟布局和页面文件App 文件夹内的 Favicon 特殊文件,带有兄弟布局和页面文件

你也可以使用代码以编程方式生成 favicon。请参阅 favicon 文档了解更多信息。

静态 Open Graph 图片

Open Graph (OG) 图片是在社交媒体中代表你的网站的图片。要向应用程序添加静态 OG 图片,在 app 文件夹的根目录创建一个 opengraph-image.png 文件。

App 文件夹内的 OG 图片特殊文件,带有兄弟布局和页面文件App 文件夹内的 OG 图片特殊文件,带有兄弟布局和页面文件

你也可以通过创建 opengraph-image.png 在文件夹结构的更深处为特定路由添加 OG 图片。例如,要为 /blog 路由创建特定的 OG 图片,在 blog 文件夹内添加一个 opengraph-image.jpg 文件。

blog 文件夹内的 OG 图片特殊文件blog 文件夹内的 OG 图片特殊文件

更具体的图片将优先于文件夹结构中其上方的任何 OG 图片。

也支持其他图片格式,如 jpegpnggif。请参阅 Open Graph 图片文档了解更多信息。

生成的 Open Graph 图片

ImageResponse 构造函数允许你使用 JSX 和 CSS 生成动态图片。这对于依赖于数据的 OG 图片很有用。

例如,要为每个博客文章生成唯一的 OG 图片,在 blog 文件夹内添加一个 opengraph-image.ts 文件,并从 next/og 导入 ImageResponse 构造函数:

app/blog/[slug]/opengraph-image.ts
import { ImageResponse } from 'next/og'
import { getPost } from '@/app/lib/data'

// 图片元数据
export const size = {
width: 1200,
height: 630,
}

export const contentType = 'image/png'

// 图片生成
export default async function Image({ params }: { params: { slug: string } }) {
const post = await getPost(params.slug)

return new ImageResponse(
(
// ImageResponse JSX 元素
<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/ogsatoriresvg 将 HTML 和 CSS 转换为 PNG。
  • 只支持 flexbox 和 CSS 属性的子集。高级布局(例如 display: grid)将不起作用。