静态资源与 robots/sitemap
本教程共 42 篇 · 第 20 篇 · 更新于 2026-07-30 · 约 6 分钟阅读
20. 静态资源与 robots/sitemap
本节目标:学会使用 Next.js 文件元数据 API 生成 robots.txt 和 sitemap.xml,掌握静态与动态两种生成方式。
文件元数据 API 概述
Next.js 提供了一组特殊文件约定,用于生成搜索引擎和社交平台需要的元数据文件:
| 文件 | 用途 | 访问路径 |
|---|---|---|
favicon.ico / icon.png | 网站图标 | /favicon.ico |
apple-icon.png | Apple 设备图标 | /apple-icon.png |
opengraph-image.png | Open Graph 分享图片 | 自动生成 |
robots.txt | 爬虫规则 | /robots.txt |
sitemap.xml | 站点地图 | /sitemap.xml |
这些文件可以放在 app 目录的任意层级,Next.js 会自动处理它们。
robots.txt
robots.txt 告诉搜索引擎爬虫哪些页面可以访问、哪些不可以。
静态 robots.txt
最简单的方式是在 app 目录下直接创建 robots.txt 文件:
# app/robots.txt
User-Agent: *
Allow: /
Disallow: /private/
Disallow: /admin/
Sitemap: https://example.com/sitemap.xml
动态 robots.ts
当需要根据条件动态生成爬虫规则时,创建 robots.ts(或 robots.js)文件:
// app/robots.ts
import type { MetadataRoute } from 'next'
export default function robots(): MetadataRoute.Robots {
return {
rules: {
userAgent: '*',
allow: '/',
disallow: ['/private/', '/admin/'],
},
sitemap: 'https://example.com/sitemap.xml',
}
}
这会生成与上一步静态文件相同的 robots.txt 内容。
针对不同爬虫定制规则
可以为不同的搜索引擎爬虫设置不同的规则:
// app/robots.ts
import type { MetadataRoute } from 'next'
export default function robots(): MetadataRoute.Robots {
return {
rules: [
{
userAgent: 'Googlebot',
allow: '/',
disallow: '/private/',
},
{
userAgent: ['Applebot', 'Bingbot'],
disallow: ['/'],
},
],
sitemap: 'https://example.com/sitemap.xml',
host: 'https://example.com',
}
}
输出结果:
User-Agent: Googlebot
Allow: /
Disallow: /private/
User-Agent: Applebot
Disallow: /
User-Agent: Bingbot
Disallow: /
Sitemap: https://example.com/sitemap.xml
robots.ts 是特殊的 Route Handler
robots.ts默认会被缓存,除非使用了请求时 API 或动态配置选项。
sitemap.xml
sitemap.xml 帮助搜索引擎发现和索引你网站的所有页面。
静态 sitemap.xml
在 app 目录下直接创建 sitemap.xml:
<!-- app/sitemap.xml -->
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url>
<loc>https://example.com</loc>
<lastmod>2026-07-30</lastmod>
<changefreq>daily</changefreq>
<priority>1.0</priority>
</url>
<url>
<loc>https://example.com/about</loc>
<lastmod>2026-07-28</lastmod>
<changefreq>monthly</changefreq>
<priority>0.8</priority>
</url>
</urlset>
动态 sitemap.ts
当页面数量多或需要从数据库获取 URL 列表时,使用 sitemap.ts:
// app/sitemap.ts
import type { MetadataRoute } from 'next'
export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
// 从数据库获取所有文章
const posts = await db.query.posts.findMany({
columns: { slug: true, updatedAt: true },
})
const postEntries: MetadataRoute.Sitemap = posts.map((post) => ({
url: `https://example.com/blog/${post.slug}`,
lastModified: post.updatedAt,
changeFrequency: 'weekly',
priority: 0.7,
}))
return [
{
url: 'https://example.com',
lastModified: new Date(),
changeFrequency: 'daily',
priority: 1,
},
{
url: 'https://example.com/about',
lastModified: new Date(),
changeFrequency: 'monthly',
priority: 0.8,
},
...postEntries,
]
}
拆分大型 sitemap
Google 限制每个 sitemap 文件最多 50,000 个 URL。当页面数量超过限制时,使用 generateSitemaps 函数拆分:
// app/product/sitemap.ts
import type { MetadataRoute } from 'next'
// 告诉 Next.js 需要生成多少个 sitemap 文件
export async function generateSitemaps() {
const totalProducts = await getProductCount()
const sitemapCount = Math.ceil(totalProducts / 50000)
return Array.from({ length: sitemapCount }, (_, i) => ({ id: i }))
}
// 每个 sitemap 文件的内容
export default async function sitemap({
id,
}: {
id: Promise<string>
}): Promise<MetadataRoute.Sitemap> {
const sitemapId = await id
const start = Number(sitemapId) * 50000
const end = start + 50000
const products = await getProducts(start, end)
return products.map((product) => ({
url: `https://example.com/product/${product.id}`,
lastModified: product.updatedAt,
}))
}
拆分后的 sitemap 可通过 /product/sitemap/0.xml、/product/sitemap/1.xml 等路径访问。
其他文件元数据
Favicon 和图标
在 app 目录下放置以下文件,Next.js 会自动生成对应的 <link> 标签:
favicon.ico- 传统 faviconicon.png/icon.jpg/icon.svg- 通用图标apple-icon.png- Apple 设备图标
Open Graph 图片
在路由目录下放置 opengraph-image.png(或 .jpg、.tsx),Next.js 会自动将其作为该路由的 OG 图片:
app/
opengraph-image.png # 根路由的 OG 图片
blog/
opengraph-image.png # /blog 路由的 OG 图片
更具体的图片会覆盖更通用的图片。例如 /blog 路由会使用 blog/opengraph-image.png 而不是根目录的。
动态 OG 图片
使用 opengraph-image.tsx 可以动态生成 OG 图片(详见第 19 章)。
类型参考
MetadataRoute 命名空间提供了完整的类型定义:
// Robots 类型
type MetadataRoute.Robots = {
rules:
| {
userAgent?: string | string[]
allow?: string | string[]
disallow?: string | string[]
crawlDelay?: number
}
| Array<...>
sitemap?: string | string[]
host?: string
}
// Sitemap 类型
type MetadataRoute.Sitemap = Array<{
url: string
lastModified?: string | Date
changeFrequency?: 'always' | 'hourly' | 'daily' | 'weekly' | 'monthly' | 'yearly' | 'never'
priority?: number
}>
小结
- robots.txt:静态文件直接创建,动态规则使用
robots.ts - sitemap.xml:静态文件直接创建,动态内容使用
sitemap.ts - 大型 sitemap:使用
generateSitemaps拆分,每个文件最多 50,000 URL - 文件位置:放在
app目录的任意层级,更具体的路径优先级更高 - 类型安全:使用
MetadataRoute命名空间获得完整类型提示