Next.js App Router 里 sitemap 怎么做:动态渲染、缓存和多 sitemap 拆分

1次阅读
没有评论

内容站做久了,sitemap.xml 很容易从一个小文件变成一个需要认真设计的入口。

文章少时,手写几条 URL 就够了;文章、分类、标签、专题页变多以后,就会遇到几个问题:数据要不要请求后端,缓存多久合适,要不要拆多个 sitemap,为什么开发时能访问、构建或部署后又提示静态生成冲突。

这篇只讲 App Router 里 sitemap 的日常处理思路,重点是把静态、动态、缓存和拆分几个概念先分清。

小站可以直接放静态 sitemap

如果站点页面很少,最简单的方式就是在 app 目录下放一个静态的 sitemap.xml

<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
  <url>
    <loc>https://example.com</loc>
    <lastmod>2026-06-11T00:00:00.000Z</lastmod>
  </url>
  <url>
    <loc>https://example.com/about</loc>
    <lastmod>2026-06-11T00:00:00.000Z</lastmod>
  </url>
</urlset>

这种方式几乎没有运行时成本,也不需要考虑接口、缓存和数据库。但它只适合页面数量稳定的小站。

只要 URL 来自数据库、CMS、博客后端或搜索索引,就不太适合长期手写。

用 `app/sitemap.ts` 生成动态列表

Next.js 的 App Router 支持用 app/sitemap.ts 生成 sitemap。常见写法是导出一个函数,返回 URL 数组。

import type { MetadataRoute } from 'next';

export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
  const posts = await fetch('https://api.example.com/posts').then((res) => res.json());

  return posts.map((post) => ({
    url: `https://example.com/posts/${post.slug}`,
    lastModified: post.updatedAt
  }));
}

这个文件很适合内容站:文章列表来自后端,生成结果交给 Next.js 输出成 XML。

但这里有一个关键点:它看起来像普通函数,本质上仍然是一个特殊的 Route Handler。也就是说,它会受到 Next.js 缓存、静态生成和动态渲染规则影响。

先决定:静态、ISR,还是每次请求生成

做 sitemap 前先问一个问题:这个 sitemap 到底多久需要更新?

如果文章一天才发几篇,可以定时缓存,没必要每次请求都打后端。

如果站点内容变化很频繁,或者后端已经有自己的缓存层,可以考虑请求时生成。

可以按这三类判断:

  • 静态生成:URL 很少,构建时确定,后续很少变化。
  • ISR:URL 会变化,但允许几分钟或几小时后再刷新。
  • 请求时生成:URL 必须尽量实时,或者 sitemap 本身只是转发后端结果。

很多 sitemap 报错,根因不是 XML 写错,而是代码里一边用了动态数据,一边又让框架按静态页面处理。

`revalidate` 适合大多数内容站

对博客、文档站、资源站来说,revalidate 通常是比较稳的选择。

export const revalidate = 3600;

export default async function sitemap() {
  const posts = await fetch('https://api.example.com/posts').then((res) => res.json());

  return posts.map((post) => ({
    url: `https://example.com/posts/${post.slug}`,
    lastModified: post.updatedAt
  }));
}

这表示 sitemap 不必每次请求都重新生成。搜索引擎访问时拿到的是缓存结果,过期后再重新生成。

好处是:

  • 不把搜索引擎爬虫流量全部打到后端。
  • 文章更新后仍然可以在可接受时间内反映到 sitemap。
  • 比完全动态生成更容易稳定部署。

缓存时间不需要一开始就追求极致。普通内容站可以先用 10 分钟、1 小时、6 小时这类粒度,再根据发布频率调整。

碰到静态生成冲突时看这几件事

如果你在 sitemap 里请求后端,又看到类似“这个路由需要动态渲染,但当前被静态生成处理”的问题,可以按顺序排查:

  1. 代码里是否用了 fetchrevalidate: 0
  2. 文件里是否显式声明了合适的缓存策略。
  3. 是否用了 cookies、headers 或其他请求时 API。
  4. 部署环境是否开启了新的缓存模型或实验能力。
  5. 当前 Next.js 版本对应的 sitemap 和 Route Segment Config 文档是否已经变化。

有些旧项目会直接加:

export const dynamic = 'force-dynamic';

这能表达“这个路由每次请求动态生成”的意图。但不要把它当成所有版本、所有配置下的唯一答案。Next.js 的缓存模型一直在调整,尤其新版本启用 Cache Components 后,一部分旧的 route segment 配置会有变化。

更稳的理解是:先确定 sitemap 的新鲜度要求,再选择静态、ISR 或请求时生成,而不是看到报错就机械套 force-dynamic

多 sitemap 不要硬塞进一个文件

搜索引擎并不要求全站所有 URL 都挤在一个 sitemap 里。内容一多,拆分反而更清楚。

常见拆分方式:

  • /sitemap.xml:站点地图索引。
  • /posts/sitemap.xml:文章 URL。
  • /categories/sitemap.xml:分类 URL。
  • /tags/sitemap.xml:标签 URL。
  • /pages/sitemap.xml:独立页面 URL。

Next.js 可以通过不同路由段放多个 sitemap.ts,也可以使用 generateSitemaps 给大列表按 ID 拆分。

拆分的好处是:

  • 单个文件更小,生成更快。
  • 某类内容异常时更容易定位。
  • 后续某个频道迁移,不会影响全站 sitemap。

对内容站来说,我更倾向于按内容类型拆,而不是按数据库分页数字裸拆。搜索工具里看问题时,poststagscategoriessitemap-1sitemap-2 更容易判断。

sitemap 不只要能访问,还要能被搜索引擎理解

生成 sitemap 后,至少检查这些点:

  1. /sitemap.xml 能通过浏览器或 curl 正常访问。
  2. 响应头是 XML 相关类型,至少不要返回 HTML 错误页。
  3. URL 使用最终规范域名,不要混用 http、测试域名或本地地址。
  4. URL 不要重复,不要带无意义参数。
  5. lastmod 来自真实更新时间,不要所有页面永远写当前时间。
  6. robots.txt 里能指向 sitemap。
  7. Search Console 或站长平台能成功读取。

这里最容易漏的是域名。开发时接口里可能返回 localhost、内网域名或旧域名;上线后 sitemap 虽然能打开,但里面全是错误 URL,这对收录没有帮助。

和后端接口配合时的一个小建议

如果 sitemap 依赖后端,后端最好提供专门的轻量接口,而不是让前端拉完整文章列表再自己裁剪。

接口只需要返回:

  • slug 或 path
  • 更新时间
  • 内容类型
  • 是否允许收录

不要把正文、作者详情、评论数量、推荐列表一起返回。搜索引擎抓 sitemap 时,前端需要的是 URL 清单,不是文章详情页的数据包。

后端也可以按频道提供多个接口,例如:

/sitemap/posts
/sitemap/categories
/sitemap/tags

这样前端生成多个 sitemap 时会更自然。

小结

Next.js App Router 里的 sitemap 可以按这个顺序处理:

  1. 页面少,用静态 app/sitemap.xml
  2. 页面来自后端,用 app/sitemap.ts
  3. 普通内容站优先考虑 revalidate,别急着每次请求都动态生成。
  4. 内容多了就拆多个 sitemap,按文章、分类、标签这类业务类型拆。
  5. 报静态/动态冲突时,先看缓存策略和当前 Next.js 版本,不要只机械套旧配置。
  6. 上线后检查 XML、规范域名、robots.txt 和搜索平台读取状态。

sitemap 的目标不是炫技,而是让搜索引擎稳定、清楚、低成本地理解你的网站结构。

参考链接

  • Next.js sitemap 官方文档:<https://nextjs.org/docs/app/api-reference/file-conventions/metadata/sitemap>
  • Next.js Route Segment Config 官方文档:<https://nextjs.org/docs/app/api-reference/file-conventions/route-segment-config>
  • Sitemaps XML 格式说明:<https://www.sitemaps.org/protocol.html>
正文完
 0
bdspAdmin
版权声明:本站原创文章,由 bdspAdmin 于2026-06-11发表,共计3686字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
评论(没有评论)