静态站点生成(Static Site Generation,简称SSG)是Next.js最引以为傲的渲染模式之一。它会在执行next build的时候把页面提前渲染成纯HTML文件,部署后直接由CDN或静态服务器返回,用户打开页面的速度极快,服务器也不需要承担运行时渲染的压力。要实现SSG,核心就是两个导出函数:getStaticProps和getStaticPaths。前者负责在构建时获取数据,后者负责告诉Next.js动态路由需要预生成哪些页面。这篇文章会结合一个博客系统的实例,把这两个API的用法彻底讲清楚。

getStaticProps:构建时获取数据的核心API
getStaticProps是一个在服务端(准确说是构建环境)执行的异步函数,它只在构建时运行一次,之后不会在用户请求时再次执行。这一点非常关键:你在浏览器端的开发者工具里看不到它的执行痕迹,因为它根本不会被打包进客户端代码。函数的返回值必须是一个对象,其中最常用的属性是props,它会被原封不动地传给页面组件。
// pages/posts.js
export default function Posts({ posts }) {
return (
<ul>
{posts.map((post) => (
<li key={post.id}>{post.title}</li>
))}
</ul>
);
}
export async function getStaticProps() {
// 构建时请求接口获取文章列表
const res = await fetch('https://api.bbccb.com/posts');
const posts = await res.json();
return {
props: { posts },
};
}除了props之外,返回对象还支持两个重要字段。revalidate用于增量静态再生(ISR),单位是秒,比如设置为60,表示页面生成后最多缓存60秒,超过这个时间再有请求进来时,Next.js会在后台重新生成页面,期间用户拿到的仍是旧版本,新版本生成后自动替换。这在内容更新频率不高的博客、文档站中非常实用,既保留了静态的速度,又兼顾了内容的时效性。
另一个字段是notFound,设为true时返回404页面。比如某篇文章已经被删除,但构建时才发现数据不存在,就可以用它来兜底。此外getStaticProps还能接收一个context参数,其中params包含了动态路由参数,preview用于预览模式,这在后面讲动态页面时会用到。
getStaticPaths:动态路由的预渲染清单
当页面文件名带有方括号,比如pages/posts/[id].js,这个页面就是动态路由。SSG模式下,Next.js必须在构建时知道所有可能的路径,否则无法预生成HTML。getStaticPaths就是用来提供这份路径清单的函数,它的返回值必须包含一个paths数组,数组每一项用params来描述路径参数,参数名必须和文件名中的方括号内容完全一致。
// pages/posts/[id].js
export async function getStaticPaths() {
const res = await fetch('https://api.bbccb.com/posts');
const posts = await res.json();
// 只预渲染最新的100篇文章
const paths = posts.slice(0, 100).map((post) => ({
params: { id: String(post.id) },
}));
return { paths, fallback: 'blocking' };
}
export async function getStaticProps({ params }) {
const res = await fetch(`https://api.bbccb.com/posts/${params.id}`);
const post = await res.json();
if (!post.id) {
return { notFound: true };
}
return {
props: { post },
revalidate: 60,
};
}这里最值得关注的是fallback这个配置,它决定了访问不在paths清单中的路径时Next.js如何处理。false表示直接返回404,适合路径集合完全固定的场景;true表示先返回一个兜底页面,同时在后台渲染真实页面,渲染完成后再替换,页面组件里可以通过router.isFallback判断当前状态并展示加载动画;'blocking'则让用户请求阻塞等待渲染完成后再返回完整页面,体验上和SSR类似,但页面生成后会被缓存供后续请求使用。
三种取值各有适用场景。数据量在几千以内、路径可枚举,选false最省心;数据量大到无法全部预渲染,或者新内容会不断产生,true或'blocking'配合ISR是更合理的选择。需要注意的是,fallback为true时,首次访问未预渲染路径的页面,组件会以空的props渲染一次,如果代码里直接访问post.title这类嵌套属性就可能报错,务必加上空值判断。
常见报错与实战注意事项
实际开发中最常见的一个报错是构建时提示无法序列化props,原因是getStaticProps返回的数据中包含了函数、Date对象或类实例这类无法被JSON序列化的内容。解决办法是在返回前手动转换,比如把Date转成时间戳或格式化后的字符串,把类实例转成普通对象。另外不要在getStaticProps里使用浏览器API,比如window或localStorage,因为它运行在Node.js环境,这些API根本不存在。
还有一点容易被忽略:getStaticProps只适合公开的、与具体用户无关的数据。如果数据依赖cookie、会话或者每次请求都不同,SSG就不合适了,应该改用getServerSideProps做服务端渲染,或者干脆走客户端获取数据的路线。此外,getStaticPaths必须和getStaticProps同时出现在同一个动态路由页面中,单独导出getStaticPaths是不生效的。
从性能角度看,构建时间会随着预渲染页面数量线性增长。如果站点有上万个页面,建议用fallback配合ISR来控制一次性生成的页面数量,只预渲染访问频率最高的入口页,其余页面留给首次访问时按需生成。同时给getStaticProps里的数据请求加上合理的缓存策略,或者直接从本地数据库、文件读取,能显著缩短构建时间。掌握这些细节后,getStaticProps与getStaticPaths的组合足以应付绝大多数内容型站点的需求,速度和维护成本都能拿到不错的平衡。
Next.jsSSGgetStaticProps修改时间:2026-09-16 04:42:30