Next 元数据(metadata)
基于配置的元数据
静态元数据还是动态元数据都只在服务端组件中支持,尽可能使用静态元数据。
静态元数据
在 layout.js 或 page.js 中,导出 Metadata 对象
| 1 |  | 
动态元数据
使用动态元数据要借助 generateMetadata 函数返回一个 Metadata 对象。
| 1 |  | 
该函数接收两个参数,props 和 parent,props 包含当前路由参数的对象,该对象有 params 和 searchParams 两个属性
params 是动态路由参数的对象,当访问非动态路由,params 为 {}
| 路由 | url | params | 
|---|---|---|
| app/shop/[slug]/page.js | /shop/1 | { slug: ‘1’ } | 
| app/shop/[tag]/[item]/page.js | /shop/1/2 | { tag: ‘1’, item: ‘2’ } | 
| app/shop/[…slug]/page.js | /shop/1/2 | { slug: [‘1’, ‘2’] } | 
searchParams 是 URLSearchParams 对象,包含了 URL 中的查询参数
| url | searchParams | 
|---|---|
| /shop?a=1 | { a: ‘1’ } | 
| /shop?a=1&b=2 | { a: ‘1’, b: ‘2’ } | 
| /shop?a=1&a=2 | { a: [‘1’, ‘2’] } | 
parent 是一个包含父路由段 metadata 对象的 promise 对象,需要使用 (await parent).openGraph 获取。
字段覆盖
Next 会对各层的元数据进行浅合并,离当前页面越近的元数据会覆盖离当前页面越远的元数据。
字段继承
当前页的元数据会继承自己没定义的上层的元数据。
| 1 |  | 
| 1 |  | 
如上,page.js 中未定义 openGraph 而 他的上层 layout 定义了,所以 page 会继承 layout 的 openGraph 字段。
JSON-LD
JSON-LD 可以向搜索引擎描述网站上的内容。 在 Next 中使用 JSON-LD 可以在 layout 或者 page 中使用 script 标签。
| 1 |  | 
基于文件的元数据
基于文件的元数据优先级更高,会覆盖基于配置的元数据。
图标
Next 的图标就是在 /app 目录下的 favicon、icon、apple-icon 图片文件。
favicon 必须要在顶层目录(如 /app 或 /src/app)下,icon 和 apple-icon 可以放在更深层的目录。
| File convention | Supported file types | Valid locations | Link ref | 
|---|---|---|---|
| favicon | .ico | app/ | |
| icon | .ico、.jpg、.jpeg、.png、.svg | app/**/* | |
| apple-icon | .jpg、.jpeg、.png | app/**/* | 
不同尺寸图标
还可以在一个目录下放多个不同尺寸 icon ,可以根据不同尺寸显示不同 icon。

使用代码生成
文件名还是 icon 或者 apple-icon 后缀为 js、ts、tsx,通过 next/og的 ImageResponse 即可生成一个图标。
| 1 |  | 
robot
robot 用于告诉搜索引擎可以爬取网站中的哪些 URL,Next 中有两种方式设置 robot。
- 静态文件
 在 app/ 下创建 robot.txt 即可1 
 2
 3
 4User-Agent: *
 Allow: /
 Disallow: /private/
 Sitemap: https://acme.com/sitemap.xml
- 代码生成
 使用 robot.js / robot.ts1 
 2
 3
 4
 5
 6
 7
 8
 9
 10export default function robots() {
 return {
 rules: {
 userAgent: '*',
 allow: '/',
 disallow: '/private/',
 },
 sitemap: 'https://acme.com/sitemap.xml',
 }
 }
站点地图 sitemap.xml
站点地图是一个 XML 文件,用于告诉搜索引擎网站的结构,Next 中可以使用静态文件 sitemap.xml 或者 sitemap.js / sitemap.ts 生成站点地图。
- 静态文件
 app/sitemap.xml:1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
 <url>
 <loc>https://acme.com</loc>
 <lastmod>2023-04-06T15:02:24.021Z</lastmod>
 <changefreq>yearly</changefreq>
 <priority>1</priority>
 </url>
 <url>
 <loc>https://acme.com/about</loc>
 <lastmod>2023-04-06T15:02:24.021Z</lastmod>
 <changefreq>monthly</changefreq>
 <priority>0.8</priority>
 </url>
 <url>
 <loc>https://acme.com/blog</loc>
 <lastmod>2023-04-06T15:02:24.021Z</lastmod>
 <changefreq>weekly</changefreq>
 <priority>0.5</priority>
 </url>
 </urlset>
- 代码生成
 使用 sitemap.js / sitemap.ts1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22export default function sitemap() {
 return [
 {
 url: 'https://acme.com',
 lastModified: new Date(),
 changeFrequency: 'yearly',
 priority: 1,
 },
 {
 url: 'https://acme.com/about',
 lastModified: new Date(),
 changeFrequency: 'monthly',
 priority: 0.8,
 },
 {
 url: 'https://acme.com/blog',
 lastModified: new Date(),
 changeFrequency: 'weekly',
 priority: 0.5,
 },
 ]
 }
metadata 属性
- title
 值可以是字符串,也可以是对象,使用对象时,default 为子路由没定义 title 的默认值,template 为子路由添加一个前缀或者后缀,并且使用 template 的话,必须同时 有 default。1 
 2
 3
 4
 5
 6
 7
 8export const metadata = {
 title: {
 template: '%s | Acme', // %s 会被替换为子路由的 title
 default: 'Acme',
 
 absolute: 'About' // 设置标题,会忽略上层路由段设置的 title.template
 },
 }
- description
 设置页面的描述
- metadataBase
 设置 metadata 字段中地址的前缀输出结果1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14// layout.js | page.js
 export const metadata = {
 metadataBase: new URL('https://acme.com'),
 alternates: {
 canonical: '/',
 languages: {
 'en-US': '/en-US',
 'de-DE': '/de-DE',
 },
 },
 openGraph: {
 images: '/og-image.png',
 },
 }使用 metadataBase 后,metadata 的地址还可以使用相对地址,Next 会进行自动合并,还会智能的处理多余的斜杠,当然如果 metadata 设置了绝对地址,metadataBase 会被忽略1 
 2
 3
 4<link rel="canonical" href="https://acme.com" />
 <link rel="alternate" hreflang="en-US" href="https://acme.com/en-US" />
 <link rel="alternate" hreflang="de-DE" href="https://acme.com/de-DE" />
 <meta property="og:image" content="https://acme.com/og-image.png" />
- openGraph输出1 
 2
 3
 4
 5
 6
 7
 8
 9export const metadata = {
 openGraph: {
 title: 'Next.js',
 description: 'The React Framework for the Web',
 type: 'article',
 publishedTime: '2023-01-01T00:00:00.000Z',
 authors: ['Seb', 'Josh'],
 },
 }1 
 2
 3
 4
 5
 6<meta property="og:title" content="Next.js" />
 <meta property="og:description" content="The React Framework for the Web" />
 <meta property="og:type" content="article" />
 <meta property="article:published_time" content="2023-01-01T00:00:00.000Z" />
 <meta property="article:author" content="Seb" />
 <meta property="article:author" content="Josh" />
- robots输出的 HTML:1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16// layout.js | page.js
 export const metadata = {
 robots: {
 index: false,
 follow: true,
 nocache: true,
 googleBot: {
 index: true,
 follow: false,
 noimageindex: true,
 'max-video-preview': -1,
 'max-image-preview': 'large',
 'max-snippet': -1,
 },
 },
 }…1 
 2
 3
 4
 5<meta name="robots" content="noindex, follow, nocache" />
 <meta
 name="googlebot"
 content="index, nofollow, noimageindex, max-video-preview:-1, max-image-preview:large, max-snippet:-1"
 />