컨텐츠로 건너뛰기

라우팅

Astro는 프로젝트 src/pages/ 디렉터리의 파일 레이아웃을 기반으로 빌드 URL을 생성하기 위해 파일 기반 라우팅을 사용합니다.

Astro는 라우트 간 탐색을 위해 표준 HTML <a> 요소를 사용합니다. 제공되는 프레임워크 특정 <Link> 컴포넌트는 없습니다.

src/pages/index.astro
<p>Astro에 대해 더 <a href="/about/">자세히</a> 알아보세요!</p>
<!-- `base: "/docs"`가 구성된 경우 -->
<p><a href="/docs/reference/">참조</a> 섹션에서 더 자세히 알아보세요!</p>

src/pages/ 디렉터리의 .astro 페이지 컴포넌트와 Markdown 및 MDX 파일 (.md, .mdx)은 자동으로 웹사이트의 페이지가 됩니다. 각 페이지의 라우트는 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의 기본 정적 출력 모드에서는 이러한 페이지가 빌드 시 생성되므로 해당 파일을 가져오는 author 목록을 미리 결정해야 합니다. SSR 모드에서는 일치하는 모든 라우트에 대한 요청 시 페이지가 생성됩니다.

모든 라우트는 빌드 시 결정되어야 하므로 동적 라우트는 params 속성이 있는 객체의 배열을 반환하는 getStaticPaths()를 내보내야 합니다. 이러한 각 객체는 해당되는 라우트를 생성합니다.

[dog].astro는 파일 이름에 동적 dog 매개변수를 정의하므로 getStaticPaths()에서 반환된 객체는 paramsdog를 포함해야 합니다. 그러면 페이지는 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>{dog}는 귀여운 강아지입니다!</div>

이는 해당 강아지 이름을 각각 표시하는 세 개의 페이지 /dogs/clifford, /dogs/rover/dogs/spot을 생성합니다.

파일 이름은 여러 매개변수를 포함할 수 있으며, 이 매개변수는 모두 getStaticPaths()params 객체에 포함되어야 합니다.

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가 생성됩니다.

매개변수는 경로의 별도 부분에 포함될 수 있습니다. 예를 들어, 위의 동일한 getStaticPaths()를 사용하는 파일 src/pages/[lang]/[version]/info.astro/en/v1/info/fr/v2/info 라우트를 생성합니다.

getStaticPaths() 함수에 제공된 params는 디코딩되지 않습니다. 매개변수 값을 디코딩해야 하는 경우 decodeURI 함수를 사용하세요.

src/pages/[slug].astro
---
export function getStaticPaths() {
return [
{ params: { slug: decodeURI("%5Bpage%5D") }}, // "[page]"로 디코딩됩니다.
]
}
---
getStaticPaths()에 대해 자세히 알아보세요.
관련 레시피: 국제화 기능 추가

URL 라우팅에서 더 많은 유연성이 필요한 경우 .astro 파일 이름에 나머지 매개변수 ([...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가 생성됩니다. (나머지 매개변수를 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"
}

예시: 여러 레벨의 동적 페이지

섹션 제목: 예시: 여러 레벨의 동적 페이지

다음 예시에서 나머지 매개변수 ([...slug])와 getStaticPaths()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>

SSR 모드에서 동적 라우트는 동일한 방식으로 정의됩니다. 임의의 문자열 또는 경로와 일치하도록 파일 이름에 [param] 또는 [...path] 대괄호를 포함합니다. 그러나 라우트는 더 이상 미리 빌드되지 않으므로 일치하는 모든 라우트에 페이지가 제공됩니다. 이러한 라우트는 “정적” 라우트가 아니므로 getStaticPaths를 사용하면 안됩니다.

요청 시 렌더링되는 라우트의 경우 파일 이름에 스프레드 표기법을 사용하는 나머지 매개변수를 하나만 사용할 수 있습니다. (예: 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>

이 페이지는 resourceid의 모든 값에 대해 제공됩니다. 예: resources/users/1, resources/colors/blue

[...slug] 예시를 SSR용으로 수정

섹션 제목: [...slug] 예시를 SSR용으로 수정

SSR 페이지는 getStaticPaths()를 사용할 수 없으므로 props를 받을 수 없습니다. 이전 예시는 객체에서 slug 매개변수의 값을 조회하여 SSR 모드에 맞게 조정할 수 있습니다. 라우트가 루트 (”/“)에 있으면 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 값을 사용하여 영구 리디렉션 매핑을 지정할 수 있습니다.

내부 리디렉션의 경우, 이는 이전 라우트 경로에서 새 라우트로의 매핑입니다. Astro v5.2.0부터는 http 또는 https로 시작하고 구문 분석할 수 있는 외부 URL로 리디렉션할 수도 있습니다.

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

이러한 리디렉션은 파일 기반 라우트와 동일한 우선 순위 규칙을 따르며 프로젝트에서 동일한 이름의 기존 페이지 파일보다 항상 낮은 우선 순위를 갖습니다. 예를 들어 프로젝트에 src/pages/old-page.astro 파일이 포함된 경우 /old-page/new-page로 리디렉션되지 않습니다.

새 라우트와 이전 라우트 모두 동일한 매개변수를 포함하는 한 동적 라우트가 허용됩니다. 예를 들면 다음과 같습니다.

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

SSR 또는 정적 어댑터를 사용하면 값을 객체로 제공하여 새 destination 외에 status 코드를 지정할 수도 있습니다.

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는 기본적으로 meta refresh 태그가 있는 HTML 파일을 출력합니다. 지원되는 어댑터는 대신 리디렉션과 함께 호스트의 구성 파일을 작성합니다.

상태 코드는 기본적으로 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()에 제공된 URL의 콘텐츠를 표시합니다.

URL 재작성은 두 개의 다른 소스 파일을 유지 관리할 필요 없이 여러 경로 (예: /products/shoes/men//products/men/shoes/)에서 동일한 콘텐츠를 표시하는 데 유용할 수 있습니다.

URL 재작성은 SEO 목적과 사용자 경험에도 유용합니다. 이를 통해 방문자를 다른 페이지로 리디렉션하거나 404 상태를 반환해야 하는 콘텐츠를 표시할 수 있습니다. URL 재작성의 일반적인 용도 중 하나는 다양한 언어 변형에 대해 동일한 현지화된 콘텐츠를 표시하는 것입니다.

다음 예제에서는 /es-CU/ (쿠바 스페인어) URL 경로를 방문했을 때 페이지의 /es/ 버전을 렌더링하기 위해 URL 재작성을 사용합니다. 방문자가 /es-cu/articles/introduction URL로 이동하면 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("/");
}
}

Astro.rewrite()에 전달된 URL이 런타임 오류를 발생시키면 Astro는 개발 환경에서 오버레이 오류를 표시하고 프로덕션 환경에서는 500 상태 코드를 반환합니다. URL이 프로젝트에 존재하지 않으면 404 상태 코드가 반환됩니다.

예를 들어 이커머스의 제품이 더 이상 제공되지 않음을 나타내기 위해 /404 페이지를 렌더링하도록 의도적으로 URL 재작성을 생성할 수 있습니다.

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

HTTP 응답 상태에 따라 조건부로 URL을 재작성하여 존재하지 않는 URL을 방문할 때 사이트의 특정 페이지를 표시할 수도 있습니다.

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

지정된 URL 재작성 경로의 콘텐츠를 표시하기 전에 Astro.rewrite() 함수는 새로운 완전한 렌더링 단계를 트리거합니다. 이렇게 하면 새 라우트/요청에 대한 모든 미들웨어가 다시 실행됩니다.

자세한 내용은 Astro.rewrite() API 참조를 확인하세요.

정의된 여러 라우트가 동일한 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/: 서버 아일랜드로 연기된 동적 컴포넌트를 제공합니다.
  • _actions/: 정의된 액션을 제공합니다.

Astro는 여러 페이지로 분할해야 하는 대규모 데이터 컬렉션에 대한 내장 페이지네이션을 지원합니다. Astro는 이전/다음 페이지 URL, 총 페이지 수 등을 포함한 일반적인 페이지네이션 속성을 생성합니다.

페이지네이션된 라우트 이름은 표준 동적 라우트와 동일한 [대괄호] 구문을 사용해야 합니다. 예를 들어, 파일 이름 /astronauts/[page].astro/astronauts/1, /astronauts/2 등에 대한 라우트를 생성하며, 여기서 [page]는 생성된 페이지 번호입니다.

다음과 같이 paginate() 함수를 사용하여 값 배열에 대한 이러한 페이지를 생성할 수 있습니다.

src/pages/astronauts/[page].astro
---
export function getStaticPaths({ paginate }) {
const astronautPages = [
{ astronaut: "Neil Armstrong" },
{ astronaut: "Buzz Aldrin" },
{ astronaut: "Sally Ride" },
{ astronaut: "John Glenn" },
];
// astronauts 배열로부터 페이지를 생성하며, 각 페이지에는 2개의 항목이 표시됩니다.
return paginate(astronautPages, { pageSize: 2 });
}
// 페이지네이션된 모든 데이터는 "page" prop으로 전달됩니다.
const { page } = Astro.props;
---
<!-- 현재 페이지 번호를 표시합니다. `Astro.params.page`를 사용할 수도 있습니다! -->
<h1>Page {page.currentPage}</h1>
<ul>
<!-- astronaut 정보 배열을 나열합니다. -->
{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 prop을 통해 데이터를 전달받습니다. page prop에는 페이지를 빌드하고 페이지 간 링크를 생성하는 데 사용할 수 있는 유용한 속성이 많이 있습니다.

interface Page<T = any> {
/** `paginate()` 함수에 전달한 데이터의 페이지 조각을 포함하는 배열입니다. */
data: T[];
/** 메타데이터 */
/** 0부터 시작하는 페이지의 첫 번째 항목 수입니다. */
start: number;
/** 0부터 시작하는 페이지의 마지막 항목 수입니다. */
end: number;
/** 총 결과 수입니다. */
total: number;
/** 1부터 시작하는 현재 페이지 번호입니다. */
currentPage: number;
/** 페이지당 항목 수입니다. (기본값: 10) */
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}
페이지네이션의 page prop에 대해 자세히 알아보세요.

페이지네이션의 고급 사용 사례는 중첩된 페이지네이션입니다. 이는 페이지네이션이 다른 동적 라우트 매개변수와 결합될 때 발생합니다. 중첩된 페이지네이션을 사용하여 페이지네이션된 컬렉션을 일부 속성 또는 태그별로 그룹화할 수 있습니다.

예를 들어, 페이지네이션된 Markdown 게시물을 일부 태그별로 그룹화하려면 다음 URL과 일치하는 /src/pages/[tag]/[page].astro 페이지를 생성하여 중첩된 페이지네이션을 사용합니다.

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

중첩된 페이지네이션은 getStaticPaths()에서 각 그룹에 대해 paginate() 결과의 배열을 반환하여 작동합니다.

다음 예제에서는 위에 나열된 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()` 결과를 반환합니다.
// Astro가 결과가 어떤 태그 그룹에 대한 것인지 알 수 있도록
// `{ params: { tag }}`를 `paginate()`에 전달해야 합니다.
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;

src/pages의 페이지 또는 디렉터리를 빌드에서 제외하려면 이름 앞에 밑줄 (_)을 붙이면 됩니다. _ 접두사가 붙은 파일은 라우터에서 인식되지 않으며 dist/ 디렉터리에 배치되지 않습니다.

이를 사용하여 페이지를 일시적으로 비활성화하고, 테스트, 유틸리티 및 컴포넌트를 관련 페이지와 동일한 폴더에 넣을 수도 있습니다.

이 예시에서는 src/pages/index.astrosrc/pages/projects/project1.md만 페이지 라우트 및 HTML 파일로 빌드됩니다.

  • 디렉터리src/pages/
    • 디렉터리_hidden-directory/
      • page1.md
      • page2.md
    • _hidden-page.astro
    • index.astro
    • 디렉터리projects/
      • _SomeComponent.astro
      • _utils.js
      • project1.md
기여하기 커뮤니티 후원하기