首页 / Astro 教程 / 动态路由与 getStaticPaths

Astro 教程

动态路由与 getStaticPaths

本教程共 56 篇 · 第 15 篇 · 更新于 2026-08-07 · 约 11 分钟阅读

AstroAstro 教程动态路由getStaticPathsrest 参数静态生成按需渲染Astro 参数

本节目标:学会用一个带方括号的文件,批量生成很多个网址,并弄懂静态模式下 getStaticPaths 怎么预先列清所有参数。

静态路由是一个文件对应一个固定网址。但现实中常有这种情况:你的博客有 100 篇文章,难道要手写 100 个 .astro 文件?当然不用。Astro 的动态路由就是来解决这事的:一个文件,生出一堆网址

动态路由长啥样

普通文件名是固定的,比如 about.astro。动态路由的文件名里带一对方括号 [ ],括号里是个参数名。比如:

src/pages/authors/[author].astro

这个 [author] 就是个「参数位」。它会匹配任意一段网址,生成每个作者各自的主页。比如访问 /authors/zhangsan,这里的 author 就等于 "zhangsan";访问 /authors/lisiauthor 就等于 "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,还能带一个 propsprops 里的数据会直接传给页面组件,页面用 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 只是网址里的一段,titletext 才是页面要显示的内容,通过 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>

这个页面能服务任意 resourceid 组合:/resources/users/1/resources/colors/blue 等等。

Warning

按需渲染模式有个限制:文件名里只能用一个剩余参数(用展开语法的那种)。比如 src/pages/[locale]/[...slug].astro 可以,但 src/pages/[...locale]/[...slug].astro 不行。

一个常见误区

初学者容易把 getStaticPaths 想得太复杂。记住三点就不会乱:

  1. 它只在静态模式下需要;按需渲染模式里既不需要、也不能写它。
  2. 它返回的数组里,每个对象的 params 必须和文件名里的方括号完全对上
  3. props 是可选的小帮手,用来顺便把显示内容带进页面,不是网址的一部分。

把这三句话记牢,动态路由就没什么可怕的。

静态还是按需,怎么选

简单一句话:

  • 网址数量能提前列清(文章、标签、作者),用静态模式 + getStaticPaths,构建出真实 HTML,又快又省。
  • 网址数量没法提前定(用户自定义路径、实时数据),用按需渲染,访问时现生成。

新手先掌握静态模式下的 getStaticPaths 就够了,它覆盖了绝大多数内容站点。

本章小结

动态路由用一个带方括号的文件批量生成网址。在默认的静态模式下,必须靠 getStaticPaths 返回 params 数组,预先列清要生成哪些网址;参数可以多个、可以是剩余参数;还能用 props 顺带传数据给页面。若开启按需渲染,则不需要 getStaticPaths,访客访问时按 Astro.params 实时生成。

下一章我们看:页面里怎么拿到这些参数和状态,以及重定向、重写、路由优先级这些进阶话题。