动态路由与 getStaticPaths
本教程共 56 篇 · 第 15 篇 · 更新于 2026-08-07 · 约 11 分钟阅读
本节目标:学会用一个带方括号的文件,批量生成很多个网址,并弄懂静态模式下
getStaticPaths怎么预先列清所有参数。
静态路由是一个文件对应一个固定网址。但现实中常有这种情况:你的博客有 100 篇文章,难道要手写 100 个 .astro 文件?当然不用。Astro 的动态路由就是来解决这事的:一个文件,生出一堆网址。
动态路由长啥样
普通文件名是固定的,比如 about.astro。动态路由的文件名里带一对方括号 [ ],括号里是个参数名。比如:
src/pages/authors/[author].astro
这个 [author] 就是个「参数位」。它会匹配任意一段网址,生成每个作者各自的主页。比如访问 /authors/zhangsan,这里的 author 就等于 "zhangsan";访问 /authors/lisi,author 就等于 "lisi"。
同一个文件能服务无数个这样的网址,你不用为每个人单独建文件。这就是「动态」的意思:网址不是写死的,而是按参数临时拼出来的。
静态模式必须先列清参数
这里要分清 Astro 的两种输出模式。默认是静态输出(static,也叫 SSG)。在静态模式下,所有页面必须在构建时就确定下来——因为构建完要生成实实在在的 HTML 文件,没法等到有人访问时再凭空变出来。
所以,动态路由在静态模式下必须回答一个问题:「你到底要生成哪些网址?」这个回答靠一个函数:getStaticPaths()。
getStaticPaths 必须返回一个数组,数组里每个对象带一个 params 属性,params 里写出方括号对应的参数值。看例子:
// src/pages/dogs/[dog].astro
---
export function getStaticPaths() {
return [
{ params: { dog: "clifford" } },
{ params: { dog: "rover" } },
{ params: { dog: "spot" } },
];
}
const { dog } = Astro.params;
---
<div>好狗狗,{dog}!</div>
构建后,会生成三个页面:/dogs/clifford、/dogs/rover、/dogs/spot,每个页面里 {dog} 显示对应的名字。
Note
Astro.params是 Astro 提供的全局对象,里面装着网址里的动态参数。访问/dogs/rover时,Astro.params.dog就是字符串"rover"。
多个参数怎么写
文件名里可以放好几个参数,方括号各自独立。比如 [lang]-[version] 用连字符连起来,就匹配 /英文-版本号/ 这种形式:
// src/pages/[lang]-[version]/info.astro
---
export function getStaticPaths() {
return [
{ params: { lang: "en", version: "v1" } },
{ params: { lang: "fr", version: "v2" } },
];
}
const { lang, version } = Astro.params;
---
这会生成 /en-v1/info 和 /fr-v2/info 两个网址。
参数也能拆到路径的不同位置。比如 src/pages/[lang]/[version]/info.astro 配合上面的 getStaticPaths,就变成 /en/v1/info 和 /fr/v2/info。关键点是:getStaticPaths 返回的 params 里,参数名和数量必须跟文件名里的方括号一一对应。少一个都会报错。
剩余参数匹配任意深度
如果想更灵活,可以用剩余参数(rest parameter) [...path],它能匹配任意深度的路径片段。注意写法是三个点加方括号。
// src/pages/sequences/[...path].astro
---
export function getStaticPaths() {
return [
{ params: { path: "one/two/three" } },
{ params: { path: "four" } },
{ params: { path: undefined } },
];
}
const { path } = Astro.params;
---
这会生成 /sequences/one/two/three、/sequences/four,以及 /sequences(把 path 设成 undefined 让它匹配最顶层)。
剩余参数还能跟具名参数混用。比如 GitHub 那种文件浏览器的网址结构:
/[org]/[repo]/tree/[branch]/[...file]
访问 /withastro/astro/tree/main/docs/public/favicon.svg 时,会被拆成:
{
org: "withastro",
repo: "astro",
branch: "main",
file: "docs/public/favicon.svg"
}
Tip剩余参数适合「路径长度不固定」的场景,比如文件树、文档层级。普通参数适合「层级固定」的场景。
参数里带特殊字符要解码
getStaticPaths 返回的 params 值不会被自动解码。如果参数里含有网址编码字符(比如 %5B 这种),需要用 decodeURI() 处理一下:
// src/pages/[slug].astro
---
export function getStaticPaths() {
return [
{ params: { slug: decodeURI("%5Bpage%5D") } }, // 解码成 "[page]"
];
}
---
大多数情况下你的参数是普通中英文或数字,用不上解码。但知道有这回事,遇到怪网址时不至于懵。
用 props 给页面传额外数据
getStaticPaths 返回的每个对象,除了 params,还能带一个 props。props 里的数据会直接传给页面组件,页面用 Astro.props 取。这特别适合「参数只是个钥匙,真正要显示的内容另有所在」的情况。
// src/pages/[...slug].astro
---
export function getStaticPaths() {
const pages = [
{ slug: undefined, title: "Astro 商店", text: "欢迎来到 Astro 商店!" },
{ slug: "products", title: "Astro 商品", text: "我们有很多好东西" },
{ slug: "products/astro-handbook", title: "Astro 终极手册", text: "想学 Astro 必读" },
];
return pages.map(({ slug, title, text }) => {
return {
params: { slug },
props: { title, text },
};
});
}
const { title, text } = Astro.props;
---
<html>
<head><title>{title}</title></head>
<body>
<h1>{title}</h1>
<p>{text}</p>
</body>
</html>
这里 slug 只是网址里的一段,title 和 text 才是页面要显示的内容,通过 props 一并带过来,页面不用自己去别处查。
Note
params决定网址长啥样;props决定页面显示啥内容。两者各司其职,这是动态路由里很常用的搭配。
按需渲染下的动态路由
如果你的站点用了适配器、开启了按需渲染(on-demand rendering),动态路由的写法有变化。在「按需渲染」模式下,页面不是构建时生成,而是访客访问时才现做。所以任何匹配的网址都会被实时服务,也就不需要、也不能用 getStaticPaths。
写法是:文件名仍然用 [param] 或 [...path] 方括号,但页面里直接读 Astro.params,不导出 getStaticPaths:
// src/pages/resources/[resource]/[id].astro
---
export const prerender = false; // 在 'server' 模式下这行可省
const { resource, id } = Astro.params;
---
<h1>{resource}: {id}</h1>
这个页面能服务任意 resource 和 id 组合:/resources/users/1、/resources/colors/blue 等等。
Warning按需渲染模式有个限制:文件名里只能用一个剩余参数(用展开语法的那种)。比如
src/pages/[locale]/[...slug].astro可以,但src/pages/[...locale]/[...slug].astro不行。
一个常见误区
初学者容易把 getStaticPaths 想得太复杂。记住三点就不会乱:
- 它只在静态模式下需要;按需渲染模式里既不需要、也不能写它。
- 它返回的数组里,每个对象的
params必须和文件名里的方括号完全对上。 props是可选的小帮手,用来顺便把显示内容带进页面,不是网址的一部分。
把这三句话记牢,动态路由就没什么可怕的。
静态还是按需,怎么选
简单一句话:
- 网址数量能提前列清(文章、标签、作者),用静态模式 +
getStaticPaths,构建出真实 HTML,又快又省。 - 网址数量没法提前定(用户自定义路径、实时数据),用按需渲染,访问时现生成。
新手先掌握静态模式下的 getStaticPaths 就够了,它覆盖了绝大多数内容站点。
本章小结
动态路由用一个带方括号的文件批量生成网址。在默认的静态模式下,必须靠 getStaticPaths 返回 params 数组,预先列清要生成哪些网址;参数可以多个、可以是剩余参数;还能用 props 顺带传数据给页面。若开启按需渲染,则不需要 getStaticPaths,访客访问时按 Astro.params 实时生成。
下一章我们看:页面里怎么拿到这些参数和状态,以及重定向、重写、路由优先级这些进阶话题。