ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Next.js 动态路由预渲染实战:generateStaticParams、ISR revalidate 与 fallback 404 处理

Next.js 动态路由预渲染实战:generateStaticParams、ISR revalidate 与 fallback 404 处理 Next.js 动态路由预渲染实战:generateStaticParams、ISR revalidate 与 fallback 404 处理用 Next.js App Router 做博客、商品详情这类「一套模板 一堆动态 id」的页面,绕不开generateStaticParams。但很多人用完发现:要么全量构建慢到崩,要么新加的数据打开就 404,要么改了内容页面死活不更新。这篇把动态路由的预渲染策略一次讲清。基本用法:构建时把已知路径静态化假设路由是app/posts/[slug]/page.tsx。generateStaticParams在构建时返回所有要预渲染的参数,Next.js 会为每个 slug 生成一个静态 HTML:// app/posts/[slug]/page.tsx export async function generateStaticParams() { const posts await fetch(https://api.example.com/posts).then(r r.json()); // 返回的每个对象的 key 要和文件夹 [slug] 对应 return posts.map((p: { slug: string }) ({ slug: p.slug })); } export default async function Post({ params }: { params: Promise{ slug: string } }) { const { slug } await params; // Next.js 15 里 params 是 Promise,要 await const post await fetch(https://api.example.com/posts/${slug}).then(r r.json()); return articleh1{post.title}/h1div{post.body}/div/article; }构建时这些页面就变成纯静态文件,访问快、对 CDN 友好。问题一:数据太多,全量预渲染构建太慢有十万篇文章时,构建时全渲染既慢又没必要。策略是只预渲染热门的,冷门的等第一次访问再生成。返回一个子集即可:export async function generateStaticParams() { const hot await fetch(https://api.example.com/posts?top100).then(r r.json()); return hot.map((p: { slug: string }) ({ slug: p.slug })); // 只预渲染 top 100 }没被预渲染的 slug,默认行为是「首次访问时按需生成并缓存」(等价于旧版的 fallback: blocking),用户几乎无感。问题二:访问了列表里不存在的 slug,要 404 而不是空白按需生成有个副作用:随便拼个不存在的 slug 也会尝试渲染。你得在页面里显式判断数据不存在时抛 404:import { notFound } from next/navigation; export default async function Post({ params }: { params: Promise{ slug: string } }) { const { slug } await params; const res await fetch(https://api.example.com/posts/${slug}); if (res.status 404) notFound(); // 触发最近的 not-found.tsx,返回真正的 404 const post await res.json(); return articleh1{post.title}/h1/article; }如果想彻底关掉「按需生成」——只允许预渲染过的路径,其余一律 404,加一行配置:export const dynamicParams false; // 不在 generateStaticParams 里的 slug 直接 404问题三:改了内容,静态页不更新静态页构建后就固定了,后台改了文章前台看不到。ISR(增量静态再生)用revalidate解决:页面到期后后台悄悄重新生成,用户先看旧的、下一次访问看新的:// 整个路由段每 60 秒最多再生一次 export const revalidate 60;如果更新时机不固定(比如编辑后台点了「发布」才要刷新),用按需重新验证更精准,在 Server Action 或 Route Handler 里调:import { revalidatePath } from next/cache; export async function publishPost(slug: string) { await savePost(slug); revalidatePath(/posts/${slug}); // 立刻让这一页失效,下次访问重建 }时间兜底(revalidate) 事件精确刷新(revalidatePath)两者配合,既不会长时间陈旧,也不用把 revalidate 设得很短白白重建。小结generateStaticParams构建时把已知动态路径预渲染成静态页,key 要对齐文件夹名[slug]。数据量大时只返回热门子集,其余按需生成;要严格白名单就dynamicParams false。按需生成必须自己notFound()兜住不存在的 id,否则会渲染空白页。内容更新用 ISR:revalidate做时间兜底,revalidatePath做事件级精确刷新,两者配合最省。记忆点:热门预渲染、冷门按需生成、不存在就 notFound、更新靠 revalidate。
返回列表