Перейти к содержимому

Маршрутизация

Astro использует маршрутизацию на основе файлов для генерации URL-адресов ваших сборок на основе схемы расположения файлов в каталоге src/pages/ вашего проекта.

Astro использует стандартные HTML-элементы <a> для навигации между маршрутами. Нет специфического для фреймворка компонента <Link>.

src/pages/index.astro
<p>Читайте далее <a href="/about/">об</a> Astro!</p>
<!-- С настроенной опцией `base: "/docs"` -->
<p>Узнайте больше в нашем <a href="/docs/reference/">справочнике</a>!</p>

Компоненты страниц .astro, а также Markdown и MDX файлы (.md, .mdx) в директории src/pages/ автоматически становятся страницами вашего сайта. Маршрут каждой страницы соответствует ее пути и имени файла в каталоге src/pages/.

# Пример: Статические маршруты
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

В имени файла страницы Astro могут быть указаны параметры динамического маршрута для создания нескольких подходящих страниц. Например, src/pages/authors/[author].astro генерирует биографическую страницу для каждого автора в вашем блоге. author становится параметром, к которому вы можете обращаться внутри страницы.

В стандартном режиме статического вывода Astro эти страницы генерируются во время сборки, поэтому вы должны заранее определить список авторов, которые получат соответствующий файл. В режиме SSR страница будет генерироваться по запросу для любого маршрута, который соответствует.

Поскольку все маршруты должны быть определены во время сборки, динамический маршрут должен экспортировать функцию getStaticPaths(), которая возвращает массив объектов со свойством params. Каждый из этих объектов будет генерировать соответствующий маршрут.

[dog].astro определяет динамический параметр dog в своем имени, поэтому объекты, возвращаемые getStaticPaths(), должны включать dog в свои params. Затем страница может получить доступ к этому параметру с помощью 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, каждая из которых отображает соответствующее имя собаки.

Имя файла может включать несколько параметров, которые должны быть включены в объекты params в 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.

Параметры могут быть включены в отдельные части пути. Например, файл src/pages/[lang]/[version]/info.astro с тем же getStaticPaths(), что и выше, сгенерирует маршруты /en/v1/info и /fr/v2/info.

Параметры, переданные функции getStaticPaths(), не декодируются. Используйте функцию decodeURI, когда вам нужно декодировать значения параметров.

src/pages/[slug].astro
---
export function getStaticPaths() {
return [
{ params: { slug: decodeURI("%5Bpage%5D") }}, // декодирует в "[page]"
]
}
---
Узнайте больше о getStaticPaths() (EN).
Связанная инструкция: Add i18n features (EN)

Если вам нужна большая гибкость в маршрутизации URL, вы можете использовать rest параметры ([...path]) в имени файла .astro для сопоставления путей файлов любой глубины:

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. (Установка параметра rest в значение undefined позволяет ему соответствовать странице верхнего уровня).

Параметры rest можно использовать с другими именованными параметрами. Например, просмотрщик файлов 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"
}

Пример: Динамические страницы на нескольких уровнях

Заголовок раздела Пример: Динамические страницы на нескольких уровнях

В следующем примере параметр rest ([...slug]) и функция props (EN) в getStaticPaths() генерируют страницы для слагов разной глубины.

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>

В режиме SSR (EN) динамические маршруты определяются точно так же: включите в имена файлов скобки [param] или [...path] для соответствия произвольным строкам или путям. Но поскольку маршруты больше не строятся заранее, страница будет обслуживаться по любому подходящему маршруту. Поскольку это не “статические” маршруты, getStaticPaths не следует использовать.

Для маршрутов, отображаемых по запросу, в имени файла может использоваться только один параметр rest с использованием spread-нотации (например, src/pages/[locale]/[...slug].astro или src/pages/[...locale]/[slug].astro, но не src/pages/[...locale]/[...slug].astro).

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

Эта страница будет предоставлена для любого значения resource и id: resources/users/1, resources/colors/blue и т. д.

Поскольку страницы SSR не могут использовать getStaticPaths(), они не могут получать props. Предыдущий пример может быть адаптирован для режима SSR путем поиска значения параметра slug в объекте. Если маршрут находится в корне (”/”), параметр slug будет иметь значение undefined. Если значение не существует в объекте, мы перенаправляем на страницу 404.

src/pages/[...slug].astro
---
const pages = [
{
slug: undefined,
title: "Магазин Astro",
text: "Добро пожаловать в магазин Astro!",
},
{
slug: "products",
title: "Продукты Astro",
text: "У нас есть множество продуктов для вас",
},
{
slug: "products/astro-handbook",
title: "Исчерпывающее руководство по Astro",
text: "Если вы хотите изучить Astro, обязательно прочитайте эту книгу.",
}
];
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>

Иногда вам нужно перенаправить читателей на новую страницу, либо постоянно, потому что структура сайта изменилась, либо в ответ на действие, такое как вход в авторизованный маршрут.

Вы можете определить правила для перенаправления пользователей на постоянно перемещаемые страницы в конфигурации Astro. Или перенаправлять пользователей динамически по мере использования ими вашего сайта.

Добавлено в: astro@2.9.0

Вы можете указать отображение постоянных переадресаций в конфигурации Astro с помощью значения redirects (EN).

Для внутренних перенаправлений это сопоставление старого пути маршрута с новым. Начиная с Astro v5.2.0, также можно перенаправлять на внешние URL-адреса, начинающиеся с http или https, которые могут быть обработаны.

astro.config.mjs
import { defineConfig } from 'astro/config';
export default defineConfig({
redirects: {
"/old-page": "/new-page",
"/blog": "https://example.com/blog"
}
});

Эти перенаправления следуют тем же правилам приоритета, что и маршруты на основе файлов и всегда будут иметь более низкий приоритет, чем существующий файл страницы с тем же именем в вашем проекте. Например, /old-page не будет перенаправлено на /new-page, если в вашем проекте содержится файл src/pages/old-page.astro.

Динамические маршруты разрешены, при условии, что как новые, так и старые маршруты содержат одни и те же параметры, например:

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

Используя SSR или статический адаптер, вы также можете предоставить объект в качестве значения, что позволит вам указать код ответа status в дополнение к новому адресу destination:

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

При запуске astro build, Astro по умолчанию выводит HTML-файлы с тегом meta refresh. Поддерживаемые адаптеры вместо этого будут выводить конфигурационный файл хоста с переадресацией.

По умолчанию код состояния будет 301. При сборке в HTML-файлы код состояния не используется сервером.

В глобальном объекте Astro метод Astro.redirect позволяет динамически перенаправлять на другую страницу. Вы можете сделать это после проверки того, вошел ли пользователь в систему, получив его сессию из куки.

src/pages/account.astro
---
import { isLoggedIn } from '../utils';
const cookie = Astro.request.headers.get('cookie');
// Если пользователь не вошел в систему, перенаправляем его на страницу входа
if (!isLoggedIn(cookie)) {
return Astro.redirect("/login");
}
---

Добавлено в: astro@4.13.0

Переписывание позволяет вам обслуживать другой маршрут без перенаправления браузера на другую страницу. Браузер будет показывать оригинальный адрес в строке URL, но вместо этого отобразит содержимое URL, предоставленного функции Astro.rewrite().

Переписывания могут быть полезны для отображения одного и того же контента по нескольким путям (например, /products/shoes/men/ и /products/men/shoes/), не требуя поддерживать два разных исходных файла.

Переписывания также полезны для SEO и пользовательского опыта. Они позволяют отображать контент, который в противном случае потребовал бы перенаправления вашего посетителя на другую страницу или вернул бы статус 404. Одним из распространённых способов использования переписываний является отображение одного и того же локализованного контента для различных вариантов языка.

Следующий пример использует переписывание для отображения версии страницы /es/, когда посещается URL-путь /es-CU/ (кубинский испанский). Когда посетитель переходит по URL-адресу /es-cu/articles/introduction, Astro отобразит содержимое, сгенерированное файлом src/pages/es/articles/introduction.astro.

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

Используйте context.rewrite() в ваших файлах эндпойнтов, чтобы перенаправить на другую страницу:

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

Если URL, переданный в Astro.rewrite(), вызывает ошибку во время выполнения, Astro покажет ошибку в виде наложения в режиме разработки и вернет код состояния 500 в продакшен-среде. Если URL не существует в вашем проекте, будет возвращен код состояния 404.

Вы можете намеренно создать переписывание для отображения вашей страницы /404, например, чтобы указать, что продукт в вашем интернет-магазине больше недоступен:

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

Вы также можете условно переписывать на основе статуса HTTP-ответа, например, чтобы отобразить определённую страницу на вашем сайте при посещении URL, который не существует:

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

Перед отображением содержимого из указанного пути переписывания функция Astro.rewrite() запустит новую полную фазу отрисовки. Это повторно выполнит любой мидлвар для нового маршрута/запроса.

Смотрите справочную информацию по API Astro.rewrite() для получения дополнительной информации.

Возможно, что несколько определённых маршрутов будут пытаться построить один и тот же путь URL. Например, все эти маршруты могут построить /posts/create:

  • Директорияsrc/pages/
    • […slug].astro
    • Директорияposts/
      • create.astro
      • [page].astro
      • [pid].ts
      • […slug].astro

Astro необходимо знать, какой маршрут должен быть использован для создания страницы. Для этого он сортирует их по порядку в соответствии со следующими правилами:

  • Зарезервированные маршруты Astro
  • Маршруты с большим количеством сегментов пути будут иметь приоритет перед менее специфичными маршрутами. В приведенном выше примере все маршруты в разделе /posts/ имеют приоритет над корневым /[...slug].astro.
  • Статические маршруты без параметров пути будут иметь приоритет над динамическими маршрутами. Например, /posts/create.astro имеет приоритет над всеми остальными маршрутами в примере.
  • Динамические маршруты с именованными параметрами имеют приоритет над остальными параметрами. Например, /posts/[page].astro имеет приоритет над /posts/[...slug].astro.
  • Предрендеренные динамические маршруты имеют приоритет над серверными динамическими маршрутами.
  • Эндпоинты имеют приоритет над страницами.
  • Маршруты на основе файлов имеют приоритет над перенаправлениями.
  • Если ни одно из вышеперечисленных правил не определяет порядок, маршруты сортируются в алфавитном порядке на основе локали по умолчанию вашей установки Node.

Учитывая приведённый выше пример, вот несколько примеров того, как правила будут сопоставлять запрашиваемый URL с маршрутом, используемым для построения 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, и т. д.

Внутренние маршруты имеют приоритет над любыми маршрутами, определёнными пользователем или интеграцией, так как они необходимы для работы функций Astro. Вот зарезервированные маршруты Astro:

  • _astro/: Обслуживает все статические ресурсы клиенту, включая CSS-документы, упакованные клиентские скрипты, оптимизированные изображения и любые ресурсы Vite.
  • _server_islands/: Обслуживает динамические компоненты, отложенные в серверный остров (EN).
  • _actions/: Обслуживает любые определённые действия (EN).

Astro поддерживает встроенную пагинацию для больших коллекций данных, которые необходимо разбить на несколько страниц. Astro генерирует общие свойства пагинации, включая URL предыдущей/следующей страницы, общее количество страниц и т. д.

Имена пагинационных маршрутов должны использовать тот же синтаксис [скобка], что и стандартные динамические маршруты. Например, имя файла /astronauts/[page].astro будет генерировать маршруты для /astronauts/1, /astronauts/2 и т. д., где [page] - это номер генерируемой страницы.

Вы можете использовать функцию paginate() для генерации этих страниц для массива значений следующим образом:

src/pages/astronauts/[page].astro
---
export function getStaticPaths({ paginate }) {
const astronautPages = [
{ astronaut: "Нил Армстронг" },
{ astronaut: "Базз Олдрин" },
{ astronaut: "Салли Райд" },
{ astronaut: "Джон Гленн" },
];
// Генерируем страницы из нашего массива астронавтов, по 2 на страницу
return paginate(astronautPages, { pageSize: 2 });
}
// Все пагинированные данные передаются по пропсу «page»
const { page } = Astro.props;
---
<!-- Отображаем номер текущей страницы. Также можно использовать `Astro.params.page`! -->
<h1>Страница {page.currentPage}</h1>
<ul>
<!-- Перечисляем массив информации об астронавтах -->
{page.data.map(({ astronaut }) => <li>{astronaut}</li>)}
</ul>

Это генерирует следующие страницы, по 2 элемента на странице:

  • /astronauts/1 - Страница 1: Отображает “Neil Armstrong” и “Buzz Aldrin”.
  • /astronauts/2 - Страница 2: отображает “Sally Ride” и “John Glenn”.

Когда вы используете функцию paginate(), каждой странице будут переданы данные через пропс page. Пропс page имеет множество полезных свойств, но вот основные из них:

interface Page<T = any> {
/** массив, содержащий часть данных страницы, которую вы передали функции paginate() */
data: T[];
/** метаданные */
/** счетчик первого элемента на странице, начиная с 0 */
start: number;
/** счетчик последнего элемента на странице, начиная с 0 */
end: number;
/** общее количество результатов */
total: number;
/** номер текущей страницы, начиная с 1 */
currentPage: number;
/** количество элементов на странице (по умолчанию: 25) */
size: number;
/** номер последней страницы */
lastPage: number;
url: {
/** url текущей страницы */
current: string;
/** url предыдущей страницы (если она есть) */
prev: string | undefined;
/** url следующей страницы (если она есть) */
next: string | undefined;
/** url первой страницы (если текущая страница не является первой) */
first: string | undefined;
/** url последней страницы (если текущая страница не является последней) */
last: string | undefined;
};
}

Следующий пример отображает текущую информацию для страницы вместе со ссылками для навигации между страницами:

src/pages/astronauts/[page].astro
---
// Выводим на страницу тот же список объектов { astronaut }, что и в предыдущем примере
export function getStaticPaths({ paginate }) { /* ... */ }
const { page } = Astro.props;
---
<h1>Страница {page.currentPage}</h1>
<ul>
{page.data.map(({ astronaut }) => <li>{astronaut}</li>)}
</ul>
{page.url.first ? <a href={page.url.first}>Первая</a> : null}
{page.url.prev ? <a href={page.url.prev}>Предыдущая</a> : null}
{page.url.next ? <a href={page.url.next}>Следующая</a> : null}
{page.url.last ? <a href={page.url.last}>Последняя</a> : null}

Более продвинутым вариантом использования пагинации является вложенная пагинация. Это когда пагинация сочетается с другими динамическими параметрами маршрута. Вы можете использовать вложенную пагинацию для группировки коллекции пагинаций по какому-либо свойству или тегу.

Например, если вы хотите сгруппировать посты в Markdown по какому-то тегу, вы можете использовать вложенную пагинацию, создав страницу /src/pages/[tag]/[page].astro, которая будет соответствовать следующим URLS:

  • /red/1 (tag=red)
  • /red/2 (tag=red)
  • /blue/1 (tag=blue)
  • /green/1 (tag=green)

Вложенная пагинация работает путем возврата массива результатов paginate() из getStaticPaths(), по одному для каждой группировки.

В следующем примере мы реализуем вложенную пагинацию для построения URL-адресов, перечисленных выше:

src/pages/[tag]/[page].astro
---
export function getStaticPaths({ paginate }) {
const allTags = ["red", "blue", "green"];
const allPosts = Object.values(import.meta.glob("../pages/post/*.md", { eager: true }));
// Для каждого тега возвращаем результат paginate().
// Убедитесь, что вы передали `{params: {tag}}` в `paginate()`.
// чтобы Astro знал, для какой группы тегов получен результат.
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;

Вы можете исключить страницы или каталоги из сборки, добавив к их именам символ подчеркивания (_). Файлы с префиксом _ не будут распознаны маршрутизатором и не будут помещены в каталог dist/.

Это можно использовать для временного отключения страниц, а также для размещения тестов, утилит и компонентов в той же папке, что и связанные с ними страницы.

В этом примере только src/pages/index.astro и src/pages/posts/post1.md будут построены как маршруты страниц и HTML-файлы.

  • Директорияsrc/pages/
    • Директория_hidden-directory/
      • page1.md
      • page2.md
    • _hidden-page.astro
    • index.astro
    • Директорияposts/
      • _SomeComponent.astro
      • _utils.js
      • post1.md
Внести свой вклад Сообщество Sponsor