Skip to content

路由

Astro 使用基于文件的路由根据项目 src/pages/ 目录的文件布局生成构建 URL。

¥Astro uses file-based routing to generate your build URLs based on the file layout of your project src/pages/ directory.

¥Navigating between pages

Astro 使用标准 HTML <a> 元素 在路由之间导航。没有提供特定于框架的 <Link> 组件。

¥Astro uses standard HTML <a> elements to navigate between routes. There is no framework-specific <Link> component provided.

src/pages/index.astro
<p>Read more <a href="/about/">about</a> Astro!</p>
<!-- With `base: "/docs"` configured -->
<p>Learn more in our <a href="/docs/reference/">reference</a> section!</p>

¥Static routes

.astro 页面组件 以及 src/pages/ 目录中的 Markdown 和 MDX 文件(.md.mdx)会自动成为你网站上的页面。每个页面的路由对应于 src/pages/ 目录中的路径和文件名。

¥.astro page components as well as Markdown and MDX Files (.md, .mdx) within the src/pages/ directory automatically become pages on your website. Each page’s route corresponds to its path and filename within the src/pages/ directory.

# Example: Static routes
src/pages/index.astro -> mysite.com/
src/pages/about.astro -> mysite.com/about
src/pages/about/index.astro -> mysite.com/about
src/pages/about/me.astro -> mysite.com/about/me
src/pages/posts/1.md -> mysite.com/posts/1

¥Dynamic routes

Astro 页面文件可以在其文件名中指定动态路由参数以生成多个匹配的页面。例如,src/pages/authors/[author].astro 为你博客上的每位作者生成一个简介页面。author 成为你可以从页面内部访问的参数。

¥An Astro page file can specify dynamic route parameters in its filename to generate multiple, matching pages. For example, src/pages/authors/[author].astro generates a bio page for every author on your blog. author becomes a parameter that you can access from inside the page.

在 Astro 默认的静态输出模式下,这些页面是在构建时生成的,因此你必须预先确定获取相应文件的 author 列表。在 SSR 模式下,将根据请求为任何匹配的路由生成页面。

¥In Astro’s default static output mode, these pages are generated at build time, and so you must predetermine the list of authors that get a corresponding file. In SSR mode, a page will be generated on request for any route that matches.

¥Static (SSG) Mode

由于所有路由都必须在构建时确定,因此动态路由必须导出 getStaticPaths(),该 getStaticPaths() 返回具有 params 属性的对象数组。这些对象中的每一个都会生成相应的路由。

¥Because all routes must be determined at build time, a dynamic route must export a getStaticPaths() that returns an array of objects with a params property. Each of these objects will generate a corresponding route.

[dog].astro 在其文件名中定义了动态 dog 参数,因此 getStaticPaths() 返回的对象必须在其 params 中包含 dog。然后页面可以使用 Astro.params 访问该参数。

¥[dog].astro defines the dynamic dog parameter in its filename, so the objects returned by getStaticPaths() must include dog in their params. The page can then access this parameter using Astro.params.

src/pages/dogs/[dog].astro
---
export function getStaticPaths() {
return [
{params: {dog: 'clifford'}},
{params: {dog: 'rover'}},
{params: {dog: 'spot'}},
];
}
const { dog } = Astro.params;
---
<div>Good dog, {dog}!</div>

这将生成三个页面:/dogs/clifford/dogs/rover/dogs/spot,分别显示对应的狗名。

¥This will generate three pages: /dogs/clifford, /dogs/rover, and /dogs/spot, each displaying the corresponding dog name.

文件名可以包含多个参数,这些参数必须全部包含在 getStaticPaths() 中的 params 对象中:

¥The filename can include multiple parameters, which must all be included in the params objects in getStaticPaths():

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

¥This will generate /en-v1/info and /fr-v2/info.

参数可以包含在路径的单独部分中。例如,文件 src/pages/[lang]/[version]/info.astro 与上面的 getStaticPaths() 相同,将生成路由 /en/v1/info/fr/v2/info

¥Parameters can be included in separate parts of the path. For example, the file src/pages/[lang]/[version]/info.astro with the same getStaticPaths() above will generate the routes /en/v1/info and /fr/v2/info.

Learn more about getStaticPaths().
Related recipe: 添加国际化功能

¥Rest parameters

如果你的 URL 路由需要更大的灵活性,你可以在 .astro 文件名中使用 剩余参数 ([...path]) 来匹配任何深度的文件路径:

¥If you need more flexibility in your URL routing, you can use a rest parameter ([...path]) in your .astro filename to match file paths of any depth:

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。(将其余参数设置为 undefined 可以使其匹配顶层页面。)

¥This will generate /sequences/one/two/three, /sequences/four, and /sequences. (Setting the rest parameter to undefined allows it to match the top level page.)

Rest 参数可以与其他命名参数一起使用。例如,GitHub 的文件查看器可以用以下动态路由表示:

¥Rest parameters can be used with other named parameters. For example, GitHub’s file viewer can be represented with the following dynamic route:

/[org]/[repo]/tree/[branch]/[...file]

在此示例中,对 /withastro/astro/tree/main/docs/public/favicon.svg 的请求将被拆分为以下命名参数:

¥In this example, a request for /withastro/astro/tree/main/docs/public/favicon.svg would be split into the following named parameters:

{
org: 'withastro',
repo: 'astro',
branch: 'main',
file: 'docs/public/favicon.svg'
}

¥Example: Dynamic pages at multiple levels

在以下示例中,剩余参数 ([...slug]) 和 getStaticPaths()props 功能为不同深度的 slugs 生成页面。

¥In the following example, a rest parameter ([...slug]) and the props feature of getStaticPaths() generate pages for slugs of different depths.

src/pages/[...slug].astro
---
export async function getStaticPaths() {
const pages = [
{
slug: undefined,
title: "Astro Store",
text: "Welcome to the Astro store!",
},
{
slug: "products",
title: "Astro products",
text: "We have lots of products for you",
},
{
slug: "products/astro-handbook",
title: "The ultimate Astro handbook",
text: "If you want to learn Astro, you must read this book.",
},
];
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>

¥Server (SSR) Mode

SSR 模式 中,动态路由的定义方式相同:在文件名中包含 [param][...path] 括号以匹配任意字符串或路径。但由于路由不再提前构建,因此页面将被提供给任何匹配的路由。由于这些不是 “static” 路由,因此不应使用 getStaticPaths

¥In SSR mode, dynamic routes are defined the same way: include [param] or [...path] brackets in your file names to match arbitrary strings or paths. But because the routes are no longer built ahead of time, the page will be served to any matching route. Since these are not “static” routes, getStaticPaths should not be used.

src/pages/resources/[resource]/[id].astro
---
const { resource, id } = Astro.params;
---
<h1>{resource}: {id}</h1>

此页面将为 resourceid 的任意值提供服务:resources/users/1resources/colors/blue

¥This page will be served for any value of resource and id: resources/users/1, resources/colors/blue, etc.

修改 SSR 的 [...slug] 示例

Section titled 修改 SSR 的 [...slug] 示例

¥Modifying the [...slug] example for SSR

由于 SSR 页面无法使用 getStaticPaths(),因此它们无法接收属性。通过查找对象中 slug 参数的值,可以将 前面的例子 适配为 SSR 模式。如果路由位于根 (”/”),则 slug 参数将为 undefined。如果对象中不存在该值,我们将重定向到 404 页面。

¥Because SSR pages can’t use getStaticPaths(), they can’t receive props. The previous example can be adapted for SSR mode by looking up the value of the slug param in an object. If the route is at the root (”/”), the slug param will be undefined. If the value doesn’t exist in the object, we redirect to a 404 page.

src/pages/[...slug].astro
---
const pages = [
{
slug: undefined,
title: 'Astro Store',
text: 'Welcome to the Astro store!',
},
{
slug: 'products',
title: 'Astro products',
text: 'We have lots of products for you',
},
{
slug: 'products/astro-handbook',
title: 'The ultimate Astro handbook',
text: 'If you want to learn Astro, you must read this book.',
}
];
const { slug } = Astro.params;
const page = pages.find((page) => page.slug === slug);
if (!page) return Astro.redirect("/404");
const { title, text } = page;
---
<html>
<head>
<title>{title}</title>
</head>
<body>
<h1>{title}</h1>
<p>{text}</p>
</body>
</html>

¥Redirects

有时,你需要将读者重定向到新页面,要么是因为站点结构发生了永久性更改,要么是为了响应登录到经过身份验证的路由等操作。

¥Sometimes you will need to redirect your readers to a new page, either permanently because your site structure has changed or in response to an action such as logging in to an authenticated route.

你可以在 Astro 配置中定义 将用户重定向到永久移动的页面 的规则。或者,动态重定向用户,因为他们使用你的网站。

¥You can define rules to redirect users to permanently-moved pages in your Astro config. Or, redirect users dynamically as they use your site.

¥Configured Redirects

Added in: astro@2.9.0

你可以使用 redirects 值在 Astro 配置中指定永久重定向的映射。对于大多数重定向,这是旧路由到新路由的映射:

¥You can specify a mapping of permanent redirects in your Astro config with the redirects value. For most redirects, this is a mapping of an old route to the new route:

astro.config.mjs
import { defineConfig } from 'astro/config';
export default defineConfig({
redirects: {
'/old-page': '/new-page'
}
});

这些重定向遵循 相同的优先级规则作为基于文件的路由,并且始终比项目中同名的现有页面文件具有较低的优先级。例如,如果你的项目包含文件 src/pages/old-page.astro,则 /old-page 将不会重定向到 /new-page

¥These redirects follow the same priority rules as file-based routes and will always take lower precedence than an existing page file of the same name in your project. For example, /old-page will not redirect to /new-page if your project contains the file src/pages/old-page.astro.

只要新旧路由包含相同的参数,就允许动态路由,例如:

¥Dynamic routes are allowed as long as both the new and old routes contain the same parameters, for example:

{
"/blog/[...slug]": "/articles/[...slug]"
}

使用 SSR 或静态适配器,你还可以提供一个对象作为值,允许你除了新的 destination 之外还指定 status 代码:

¥Using SSR or a static adapter, you can also provide an object as the value, allowing you to specify the status code in addition to the new destination:

astro.config.mjs
import { defineConfig } from 'astro/config';
export default defineConfig({
redirects: {
'/old-page': {
status: 302,
destination: '/new-page'
}
}
});

运行 astro build 时,Astro 默认会输出带有 元刷新 标签的 HTML 文件。支持的适配器将使用重定向写出主机的配置文件。

¥When running astro build, Astro will output HTML files with the meta refresh tag by default. Supported adapters will instead write out the host’s configuration file with the redirects.

状态码默认为 301。如果构建为 HTML 文件,服务器不会使用状态代码。

¥The status code is 301 by default. If building to HTML files the status code is not used by the server.

¥Dynamic redirects

Astro 全局上,Astro.redirect 方法允许你动态重定向到另一个页面。你可以在通过从 cookie 获取会话来检查用户是否登录后执行此操作。

¥On the Astro global, the Astro.redirect method allows you to redirect to another page dynamically. You might do this after checking if the user is logged in by getting their session from a cookie.

src/pages/account.astro
---
import { isLoggedIn } from '../utils';
const cookie = Astro.request.headers.get('cookie');
// If the user is not logged in, redirect them to the login page
if (!isLoggedIn(cookie)) {
return Astro.redirect('/login');
}
---
<html>
<!-- Page here... -->
</html>

¥Rewrites

Added in: astro@4.13.0

重写允许你提供不同的路由,而无需将浏览器重定向到不同的页面。浏览器将在 URL 栏中显示原始地址,但将显示提供给 Astro.rewrite() 的 URL 的内容。

¥A rewrite allows you to serve a different route without redirecting the browser to a different page. The browser will show the original address in the URL bar, but will instead display the content of the URL provided to Astro.rewrite().

重写可用于在多个路径(例如 /products/shoes/men//products/men/shoes/)上显示相同内容,而无需维护两个不同的源文件。

¥Rewrites can be useful for showing the same content at multiple paths (e.g. /products/shoes/men/ and /products/men/shoes/) without needing to maintain two different source files.

重写对于 SEO 目的和用户体验也很有用。它们允许你显示否则需要将访问者重定向到其他页面或返回 404 状态的内容。重写的一种常见用途是针对语言的不同变体显示相同的本地化内容。

¥Rewrites are also useful for SEO purposes and user experience. They allow you to display content that otherwise would require redirecting your visitor to a different page or would return a 404 status. One common use of rewrites is to show the same localized content for different variants of a language.

以下示例在访问 /es-CU/(古巴西班牙语)URL 路径时使用重写来渲染页面的 /es/ 版本。当访问者导航到 URL /es-cu/articles/introduction 时,Astro 将渲染文件 src/pages/es/articles/introduction.astro 生成的内容。

¥The following example uses a rewrite to render the /es/ version of a page when the /es-CU/ (Cuban Spanish) URL path is visited. When a visitor navigates to the URL /es-cu/articles/introduction, Astro will render the content generated by the file src/pages/es/articles/introduction.astro.

src/pages/es-cu/articles/introduction.astro
---
return Astro.rewrite("/es/articles/introduction")
---

在你的端点文件中使用 context.rewrite() 重新路由到不同的页面:

¥Use context.rewrite() in your endpoint files to reroute to a different page:

src/pages/api.js
export function GET(context) {
if (!context.locals.allowed) {
return context.rewrite("/")
}
}

如果传递给 Astro.rewrite() 的 URL 发出运行时错误,Astro 将在开发中显示覆盖错误并在生产中返回 500 状态代码。如果 URL 不存在于你的项目中,则将返回 404 状态代码。

¥If the URL passed to Astro.rewrite() emits a runtime error, Astro will show the overlay error in development and return a 500 status code in production. If the URL does not exist in your project, a 404 status code will be returned.

你可以有意创建重写来渲染你的 /404 页面,例如指示你的电子商务商店中的产品不再可用:

¥You can intentionally create a rewrite to render your /404 page, for example to indicate that a product in your e-commerce shop is no longer available:

src/pages/[item].astro
---
const { item } = Astro.params;
if (!itemExists(item)) {
return Astro.rewrite("/404")
}
---
<div>...</div>

你还可以根据 HTTP 响应状态有条件地重写,例如在访问不存在的 URL 时在你的网站上显示某个页面:

¥You can also conditionally rewrite based on an HTTP response status, for example to display a certain page on your site when visiting a URL that doesn’t exist:

src/middleware.mjs
export const onRequest = async (context, next) => {
const response = await next();
if (response.status === 404) {
return context.rewrite("/");
}
return response;
}

在显示来自指定重写路径的内容之前,函数 Astro.rewrite() 将触发一个新的完整渲染阶段。这会重新执行新路由/请求的任何中间件。

¥Before displaying the content from the specified rewrite path, the function Astro.rewrite() will trigger a new, complete rendering phase. This re-executes any middleware for the new route/request.

See the Astro.rewrite() API reference for more information.

¥Route Priority Order

多个定义的路由可能会尝试构建相同的 URL 路径。例如,所有这些路由都可以构建 /posts/create

¥It’s possible for multiple defined routes to attempt to build the same URL path. For example, all of these routes could build /posts/create:

  • Directorysrc/pages/
    • […slug].astro
    • Directoryposts/
      • create.astro
      • [page].astro
      • [pid].ts
      • […slug].astro

Astro 需要知道应该使用哪条路由来构建页面。为此,它会按以下规则对它们进行排序:

¥Astro needs to know which route should be used to build the page. To do so, it sorts them according to the following rules in order:

  • 具有更多路径段的路由将优先于不太具体的路由。在上面的例子中,/posts/ 下的所有路由在根上都优先于 /[...slug].astro

  • 没有路径参数的静态路由将优先于动态路由。例如/posts/create.astro 优先于示例中的所有其他路由。

  • 使用命名参数的动态路由优先于其余参数。例如/posts/[page].astro 优先于 /posts/[...slug].astro

  • 预渲染的动态路由优先于服务器动态路由。

  • 端点优先于页面。

  • 基于文件的路由优先于重定向。

  • 如果上述规则均未决定顺序,则路由将根据 Node 安装的默认语言环境按字母顺序排序。

鉴于上面的示例,以下是规则如何将请求的 URL 与用于构建 HTML 的路由相匹配的几个示例:

¥Given the example above, here are a few examples of how the rules will match a requested URL to the route used to build the HTML:

  • pages/posts/create.astro - 将仅构建 /posts/create

  • pages/posts/[pid].ts - 将构建 /posts/abc/posts/xyz 等,但不会构建 /posts/create

  • pages/posts/[page].astro - 将构建 /posts/1/posts/2 等,但不会构建 /posts/create/posts/abc/posts/xyz

  • pages/posts/[...slug].astro - 将构建 /posts/1/2/posts/a/b/c 等,但不会构建 /posts/create/posts/1/posts/abc 等。

  • pages/[...slug].astro - 将构建 /abc/xyz/abc/xyz 等,但不会构建 /posts/create/posts/1/posts/abc 等。

¥Pagination

Astro 支持针对需要拆分为多个页面的大量数据的内置分页。Astro 将生成常见的分页属性,包括上一页/下一页 URL、总页数等。

¥Astro supports built-in pagination for large collections of data that need to be split into multiple pages. Astro will generate common pagination properties, including previous/next page URLs, total number of pages, and more.

分页路由名称应使用与标准动态路由相同的 [bracket] 语法。例如,文件名 /astronauts/[page].astro 将生成 /astronauts/1/astronauts/2 等的路由,其中 [page] 是生成的页码。

¥Paginated route names should use the same [bracket] syntax as a standard dynamic route. For instance, the file name /astronauts/[page].astro will generate routes for /astronauts/1, /astronauts/2, etc, where [page] is the generated page number.

你可以使用 paginate() 函数为值数组生成这些页面,如下所示:

¥You can use the paginate() function to generate these pages for an array of values like so:

src/pages/astronauts/[page].astro
---
export async function getStaticPaths({ paginate }) {
const astronautPages = [{
astronaut: 'Neil Armstrong',
}, {
astronaut: 'Buzz Aldrin',
}, {
astronaut: 'Sally Ride',
}, {
astronaut: 'John Glenn',
}];
// Generate pages from our array of astronauts, with 2 to a page
return paginate(astronautPages, { pageSize: 2 });
}
// All paginated data is passed on the "page" prop
const { page } = Astro.props;
---
<!--Display the current page number. Astro.params.page can also be used!-->
<h1>Page {page.currentPage}</h1>
<ul>
<!--List the array of astronaut info-->
{page.data.map(({ astronaut }) => <li>{astronaut}</li>)}
</ul>

这会生成以下页面,每个页面包含 2 个项目:

¥This generates the following pages, with 2 items to a page:

  • /astronauts/1 - 第 1 页:显示 “尼尔阿姆斯特朗” 和 “巴兹·奥尔德林”

  • /astronauts/2 - 第 2 页:显示 “Sally Ride” 和 “约翰·格伦”

¥The page prop

当你使用 paginate() 函数时,每个页面将通过 page 属性传递其数据。page prop 有许多有用的属性,你可以使用它们来构建页面和它们之间的链接:

¥When you use the paginate() function, each page will be passed its data via a page prop. The page prop has many useful properties that you can use to build pages and links between them:

interface Page<T = any> {
/** array containing the page’s slice of data that you passed to the paginate() function */
data: T[];
/** metadata */
/** the count of the first item on the page, starting from 0 */
start: number;
/** the count of the last item on the page, starting from 0 */
end: number;
/** total number of results */
total: number;
/** the current page number, starting from 1 */
currentPage: number;
/** number of items per page (default: 10) */
size: number;
/** number of last page */
lastPage: number;
url: {
/** url of the current page */
current: string;
/** url of the previous page (if there is one) */
prev: string | undefined;
/** url of the next page (if there is one) */
next: string | undefined;
/** url of the first page (if the current page is not the first page) */
first: string | undefined;
/** url of the last page (if the current page in not the last page) */
last: string | undefined;
};
}

以下示例显示页面的当前信息以及用于在页面之间导航的链接:

¥The following example displays current information for the page along with links to navigate between pages:

src/pages/astronauts/[page].astro
---
// Paginate same list of { astronaut } objects as the previous example
export async function getStaticPaths({ paginate }) { /* ... */ }
const { page } = Astro.props;
---
<h1>Page {page.currentPage}</h1>
<ul>
{page.data.map(({ astronaut }) => <li>{astronaut}</li>)}
</ul>
{page.url.first ? <a href={page.url.first}>First</a> : null}
{page.url.prev ? <a href={page.url.prev}>Previous</a> : null}
{page.url.next ? <a href={page.url.next}>Next</a> : null}
{page.url.last ? <a href={page.url.last}>Last</a> : null}
Learn more about the pagination page prop.

¥Nested Pagination

分页的更高级用例是嵌套分页。这是当分页与其他动态路由参数结合时。你可以使用嵌套分页按某些属性或标签对分页集合进行分组。

¥A more advanced use-case for pagination is nested pagination. This is when pagination is combined with other dynamic route params. You can use nested pagination to group your paginated collection by some property or tag.

例如,如果你想按某个标签对分页 Markdown 帖子进行分组,则可以通过创建与以下 URL 匹配的 /src/pages/[tag]/[page].astro 页面来使用嵌套分页:

¥For example, if you want to group your paginated Markdown posts by some tag, you would use nested pagination by creating a /src/pages/[tag]/[page].astro page that would match the following URLS:

  • /red/1(标签=红色)

  • /red/2(标签=红色)

  • /blue/1(标签=蓝色)

  • /green/1(标签=绿色)

嵌套分页的工作原理是从 getStaticPaths() 返回一组 paginate() 结果,每个分组一个。

¥Nested pagination works by returning an array of paginate() results from getStaticPaths(), one for each grouping.

在下面的示例中,我们将实现嵌套分页来构建上面列出的 URL:

¥In the following example, we will implement nested pagination to build the URLs listed above:

src/pages/[tag]/[page].astro
---
export async function getStaticPaths({ paginate }) {
const allTags = ['red', 'blue', 'green'];
const allPosts = await Astro.glob('../../posts/*.md');
// For every tag, return a paginate() result.
// Make sure that you pass `{params: {tag}}` to `paginate()`
// so that Astro knows which tag grouping the result is for.
return allTags.flatMap((tag) => {
const filteredPosts = allPosts.filter((post) => post.frontmatter.tag === tag);
return paginate(filteredPosts, {
params: { tag },
pageSize: 10
});
});
}
const { page } = Astro.props;
const params = Astro.params;

¥Excluding pages

你可以通过在页面或目录名称前添加下划线 (_) 来排除页面或目录的构建。带有 _ 前缀的文件不会被路由识别,也不会被放入 dist/ 目录中。

¥You can exclude pages or directories from being built by prefixing their names with an underscore (_). Files with the _ prefix won’t be recognized by the router and won’t be placed into the dist/ directory.

你可以使用它来暂时禁用页面,也可以将测试、实用程序和组件放在与其相关页面相同的文件夹中。

¥You can use this to temporarily disable pages, and also to put tests, utilities, and components in the same folder as their related pages.

在此示例中,仅 src/pages/index.astrosrc/pages/posts/post1.md 将构建为页面路由和 HTML 文件。

¥In this example, only src/pages/index.astro and src/pages/posts/post1.md will be built as page routes and HTML files.

  • Directorysrc/pages/
    • Directory_hidden-directory/
      • page1.md
      • page2.md
    • _hidden-page.astro
    • index.astro
    • Directoryposts/
      • _SomeComponent.astro
      • _utils.js
      • post1.md
Astro 中文网 - 粤ICP备13048890号