元数据和 OG 图片
元数据 API 可用于定义应用程序元数据以改善 SEO 和网页可分享性,包括:
- 静态 
metadata对象 - 动态 
generateMetadata函数 - 特殊的文件约定,可用于添加静态或动态生成的favicon和OG 图片。
 
使用上述所有选项,Next.js 将自动为你的页面生成相关的 <head> 标签,可以在浏览器的开发者工具中检查。
默认字段
有两个默认的 meta 标签,即使路由没有定义元数据,也会始终添加:
- meta charset 标签设置网站字符编码。
 - meta viewport 标签设置网站的视口宽度和缩放比例,以适应不同设备。
 
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
其他元数据字段可以使用 Metadata 对象(用于静态元数据)或 generateMetadata 函数(用于生成的元数据)来定义。
静态元数据
要定义静态元数据,从静态 layout.js 或 page.js 文件导出 Metadata 对象。例如,要向博客路由添加标题和描述:
- TypeScript
 - JavaScript
 
import type { Metadata } from 'next'
export const metadata: Metadata = {
  title: 'My Blog',
  description: '...',
}
export default function Page() {}
export const metadata = {
  title: 'My Blog',
  description: '...',
}
export default function Page() {}
你可以在 generateMetadata 文档中查看可用选项的完整列表。
生成的元数据
你可以使用 generateMetadata 函数来 fetch 依赖于数据的元数据。例如,要获取特定博客文章的标题和描述:
- TypeScript
 - JavaScript
 
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) {}
export async function generateMetadata({ params, searchParams }, parent) {
  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 }) {}
流式元数据
对于动态渲染的页面,如果解析 generateMetadata 可能会阻塞渲染,Next.js 会单独流式传输解析的元数据,并在准备好后立即将其注入到 HTML 中。
静态渲染的页面不使用此行为,因为元数据在构建时解析。
了解更多关于流式元数据。
缓存数据请求
在某些情况下,你可能需要为元数据和页面本身获取相同的数据。为了避免重复请求,你可以使用 React 的 cache 函数来记忆化返回值,只获取一次数据。例如,要获取博客文章信息用于元数据和页面:
- TypeScript
 - JavaScript
 
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
})
import { cache } from 'react'
import { db } from '@/app/lib/db'
// getPost 将被使用两次,但只执行一次
export const getPost = cache(async (slug) => {
  const res = await db.query.posts.findFirst({ where: eq(posts.slug, slug) })
  return res
})
- TypeScript
 - JavaScript
 
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>
}
基于文件的元数据
以下特殊 文件可用于元数据:
- favicon.ico、apple-icon.jpg 和 icon.jpg
 - opengraph-image.jpg 和 twitter-image.jpg
 - robots.txt
 - sitemap.xml
 
你可以将这些用于静态元数据,或者可以使用代码以编程方式生成这些文件。
Favicon
Favicon 是在书签和搜索结果中代表你的网站的小图标。要向应用程序添加 favicon,创建一个 favicon.ico 并添加到 app 文件夹的根目录。
你也可以使用代码以编程方式生成 favicon。请参阅 favicon 文档了解更多信息。
静态 Open Graph 图片
Open Graph (OG) 图片是在社交媒体中代表你的网站的图片。要向应用程序添加静态 OG 图片,在 app 文件夹的根目录创建一个 opengraph-image.png 文件。


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


更具体的图片将优先于文件夹结构中其上方的任何 OG 图片。
也支持其他图片格式,如
jpeg、png和gif。请参阅 Open Graph 图片文档了解更多信息。
生成的 Open Graph 图片
ImageResponse 构造函数允许你使用 JSX 和 CSS 生成动态图片。这对于依赖于数据的 OG 图片很有用。
例如,要为每个博客文章生成唯一的 OG 图片,在 blog 文件夹内添加一个 opengraph-image.ts 文件,并从 next/og 导入 ImageResponse 构造函数:
- TypeScript
 - JavaScript
 
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>
    )
  )
}
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 }) {
  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/og、satori和resvg将 HTML 和 CSS 转换为 PNG。- 只支持 flexbox 和 CSS 属性的子集。高级布局(例如
 display: grid)将不起作用。