ルーティング
Astroはファイルベースルーティングを使用して、プロジェクトのsrc/pages/ディレクトリのファイルレイアウトを元にビルドURLを生成します。
ページ間の移動
Section titled “ページ間の移動”Astroでは、ルート間の移動に標準的なHTMLの<a>要素を使用します。フレームワーク固有の<Link>コンポーネントは提供されていません。
<p>Astroの<a href="/about/">概要</a>についてもっと読む!</p>
<!-- `base: "/docs"`が設定されている場合 --><p><a href="/docs/reference/">リファレンス</a>セクションでもっと学びましょう!</p>静的ルーティング
Section titled “静的ルーティング”src/pages/ディレクトリにある.astroページコンポーネント、MarkdownとMDXファイル(.md、.mdx)は、自動的にウェブサイトのページとなります。各ページのルートは、src/pages/ディレクトリ内における自身のパスとファイル名に対応します。
# 静的ルーティングの例src/pages/index.astro -> mysite.com/src/pages/about.astro -> mysite.com/aboutsrc/pages/about/index.astro -> mysite.com/aboutsrc/pages/about/me.astro -> mysite.com/about/mesrc/pages/posts/1.md -> mysite.com/posts/1Astroのプロジェクトでは、別途「ルーティング設定」を管理する必要はありません。src/pages/ディレクトリにファイルを配置すると、新しいルートが自動的に作成されます。静的ビルドでは、build.format (EN)設定オプションを使用してファイルの出力形式をカスタマイズできます。
動的ルーティング
Section titled “動的ルーティング”Astroページファイルのファイル名に動的ルートパラメータを指定すると、ファイルにマッチするページを複数生成できます。たとえばsrc/pages/authors/[author].astroは、ブログの各著者に対してプロフィールページを生成します。authorは、ページ内からアクセス可能なパラメータとなります。
Astroのデフォルトの静的出力モードでは、これらのページはビルド時に生成されるため、authorと対応するファイルを取得する場合、それらのリストを事前に決めておく必要があります。SSRモードでは、ルートにマッチしたリクエストに応じてページが生成されます。
静的(SSG)モード
Section titled “静的(SSG)モード”すべてのルートをビルド時に決める必要があるため、動的ルートはgetStaticPaths()をエクスポートし、そこでparamsプロパティをもつオブジェクトの配列を返す必要があります。各オブジェクトは対応するルートを生成します。
[dog].astroはファイル名に動的なdogパラメータが定義されているため、getStaticPaths()から返されるオブジェクトのparamsにはdogを含める必要があります。Astro.paramsを使用してページからこのパラメータにアクセスできます。
---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という3つのページが生成され、各ページでは対応する犬の名前が表示されます。
ファイル名には複数のパラメータを含められますが、これらをすべてgetStaticPaths()のparamsオブジェクトに含める必要があります。
---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のルートを生成します。
paramsのデコード
Section titled “paramsのデコード”getStaticPaths()関数が返すparamsはデコードされません。パラメータ値をデコードする必要がある場合は、decodeURI()を使用してください。
---export function getStaticPaths() { return [ { params: { slug: decodeURI("%5Bpage%5D") }}, // "[page]"にデコードされます ]}---getStaticPaths (EN)についてもっと詳しく見る。
レストパラメーター
Section titled “レストパラメーター”より柔軟なURLルーティングが必要な場合は、.astroファイル名にレストパラメータ([...path])を使用することで、任意の深さのファイルパスにマッチさせられます。
---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'}複数レベルの動的ページの例
Section titled “複数レベルの動的ページの例”以下の例は、レストパラメータ([...slug])とgetStaticPaths()のprops (EN)機能を使用して、異なる深さのスラグに対してページを生成します。
---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>オンデマンド動的ルート
Section titled “オンデマンド動的ルート”オンデマンドレンダリングでも、動的ルートの定義方法は同じです。ファイル名に[param]や[...path]などのブラケット表記を付ければ、任意の文字列やパスにマッチさせられます。ただし、これらのルートはビルド時に生成されないため、一致するURLへのリクエストごとにページが配信されます。静的ルートではないため、getStaticPaths()は使用しません。
オンデマンドレンダリング用のルートでは、スプレッド構文([...param])によるレストパラメータはファイル名につき1つだけ指定できます。たとえばsrc/pages/[locale]/[...slug].astroやsrc/pages/[...locale]/[slug].astroは許可されますが、src/pages/[...locale]/[...slug].astroは許可されません。
---export const prerender = false; // 'server'モードでは不要const { resource, id } = Astro.params;---<h1>{resource}: {id}</h1>このページは、resources/users/1やresources/colors/blueなど、任意のresourceとidに対して提供されます。
[...slug]の例をSSR用に変更する
Section titled “[...slug]の例をSSR用に変更する”SSRページではgetStaticPaths()を使用できないため、propsを受け取れません。しかし、オブジェクト内のslugパラメータの値を参照することで、前の例をSSRモードにも対応させられます。ルーティングが”/“の場合、slugパラメータはundefinedになります。以下の例では値がオブジェクトに存在しない場合は、404ページにリダイレクトしています。
---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>リダイレクト
Section titled “リダイレクト”読者を新しいページにリダイレクトしなければならない場合があります。サイトの構造が変更されたために永久的にリダイレクトする必要がある場合や、認証されたルートにログインするといったアクションに応じておこなう場合などです。
Astroの設定で、永久的に移動したページにユーザーをリダイレクトするルールを定義できます。また、ユーザーがサイトを利用した際に動的にリダイレクトすることもできます。
リダイレクトの設定
Section titled “リダイレクトの設定”
追加:
astro@2.9.0
redirects (EN)値を使用して、Astroの設定から永久的なリダイレクトのマッピングを指定できます。
サイト内のリダイレクトを定義する場合、これは古いルートから新しいルートへのマッピングとなります。Astro v5.2.0以降では、httpまたはhttpsで始まる解析可能な外部URLへのリダイレクトも可能です。
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または静的アダプターを使用するとオブジェクトを値として設定でき、そこでstatusコードや新しいdestinationを指定できます。
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ファイルをビルドする場合、ステータスコードはサーバーによって使用されません。
動的リダイレクト
Section titled “動的リダイレクト”AstroグローバルのAstro.redirectメソッドを使用すると、別のページに動的にリダイレクトできます。たとえばクッキーからセッションを取得してユーザーのログイン状態を確認した後などにこれをおこないます。
---import { isLoggedIn } from '../utils';
const cookie = Astro.request.headers.get('cookie');
// ユーザーがログインしていない場合は、ログインページにリダイレクトしますif (!isLoggedIn(cookie)) { return Astro.redirect('/login');}---AstroはオンデマンドレンダリングでHTMLストリーミングを使用するため、リダイレクトは子コンポーネント内ではなく、ページレベルで実行する必要があります。
追加:
astro@4.13.0
リライトを使用すると、ブラウザを別ページへリダイレクトせずに別のURLパスの内容を提供できます。アドレスバーには元のURLが表示されたままですが、実際にはAstro.rewrite() (EN)で指定したページが表示されます。
永続的に移動したコンテンツや、ユーザーを異なるページに誘導したい場合(ログイン後のユーザーダッシュボードなど)には、代わりにリダイレクトを使用してください。
リライトは、複数のパスで同じコンテンツを表示する場合(例:/products/shoes/men/と/products/men/shoes/)に便利で、2つの異なるソースファイルを別々にメンテナンスする必要がなくなります。
リライトはSEOとユーザー体験の両面で有効です。リダイレクトせずに済むケースや、本来404を返すURLでもコンテンツを表示できます。リライトの一般的な使用例は、言語の異なるバリアントに対して同じローカライズされたコンテンツを表示することです。
次の例では、/es-CU/(キューバスペイン語)にアクセスするとリライトにより/es/バージョンのページを表示します。/es-cu/articles/introductionへのリクエストでは、src/pages/es/articles/introduction.astroのコンテンツが表示されます。
---return Astro.rewrite("/es/articles/introduction");---エンドポイントファイルでcontext.rewrite()を使用して、別のページにルーティングできます。
export function GET(context) { if (!context.locals.allowed) { return context.rewrite("/"); }}Astro.rewrite()に渡されたURLが実行時エラーを発生させる場合、Astroは開発環境ではオーバーレイエラーを表示し、本番環境では500ステータスコードを返します。URLがプロジェクトに存在しない場合は、404ステータスコードが返されます。
意図的にリライトを使って/404ページをレンダリングすることもできます。たとえば、eコマースショップの商品が利用できなくなったことを示す場合です。
---const { item } = Astro.params;
if (!itemExists(item)) { return Astro.rewrite("/404");}---また、HTTPレスポンスステータスに基づいて条件付きでリライトすることもできます。たとえば、存在しないURLにアクセスした際に、サイトの特定のページを表示できます。
export const onRequest = async (context, next) => { const response = await next(); if (response.status === 404) { return context.rewrite("/"); } return response;}指定されたリライトパスからコンテンツを表示する前に、Astro.rewrite()関数は新しい完全なレンダリングフェーズをトリガーします。これにより、新しいルーティング/リクエストに対するミドルウェアが再実行されます。
Astro.rewrite()APIリファレンス (EN)についてもっと詳しく見る。
ルーティングの優先順位
Section titled “ルーティングの優先順位”複数のルートが同じ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/:定義されたアクションを提供します。
ページネーション
Section titled “ページネーション”Astroは、複数のページに分割する必要がある大規模なデータコレクションのために、ページネーションを組み込みでサポートしています。Astroは、前ページと次ページのURL、総ページ数など、一般的なページネーションプロパティを生成します。
ページネーションされるルート名には、標準的な動的ルートと同じ[ブラケット]構文を使用する必要があります。たとえば、ファイル名/astronauts/[page].astroは/astronauts/1、/astronauts/2などのルートを生成し、[page]は生成されるページ番号となります。
paginate()関数を使用すると、次のように値の配列に対してこれらのページを生成できます。
---import type { GetStaticPaths } from "astro";
export const getStaticPaths = (({ paginate }) => { const astronautPages = [ { astronaut: "ニール・アームストロング" }, { astronaut: "バズ・オルドリン" }, { astronaut: "サリー・ライド" }, { astronaut: "ジョン・グレン" }, ];
// 宇宙飛行士の配列から、1ページに2人ずつ入るようにページを生成します return paginate(astronautPages, { pageSize: 2 });}) satisfies GetStaticPaths;
// ページネーションされたデータは、すべて"page"プロパティとして渡されますconst { page } = Astro.props;---
<!-- 現在のページ番号を表示します。`Astro.params.page`も使用できます! --><h1>ページ {page.currentPage}</h1><ul> <!-- 宇宙飛行士情報の配列を列挙します --> {page.data.map(({ astronaut }) => <li>{astronaut}</li>)}</ul>これで、1ページに2つのアイテムが配置された、以下のページが生成されます。
/astronauts/1- 1ページ目には「ニール・アームストロング」と「バズ・オルドリン」を表示します/astronauts/2- 2ページ目には「サリー・ライド」と「ジョン・グレン」を表示します
pageプロパティ
Section titled “pageプロパティ”paginate()関数を使用すると、各ページのデータはpageプロパティで渡されます。pageプロパティは多くの便利なプロパティを持っています。
interface Page<T = any> { /** paginate() 関数に渡されたページのデータを含む配列 */ data: T[]; /** メタデータ */ /** 0から始まる、ページ上の最初のアイテムのインデックス */ start: number; /** 0から始まる、ページ上の最後のアイテムのインデックス */ end: number; /** 結果の総数 */ total: number; /** 1から始まる、現在のページ番号 */ currentPage: number; /** 1ページあたりのアイテム数(デフォルトは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; };}以下の例では、ページの現在の情報とページ間を移動するためのリンクを表示しています。
---import type { GetStaticPaths } from "astro";
// 前の例と同じように、{ astronaut } オブジェクトのリストをページネーションしますexport const getStaticPaths = (({ paginate }) => { /* ... */}) satisfies GetStaticPaths;
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 (EN)についてもっと学ぶ。
ネストされたページネーション
Section titled “ネストされたページネーション”ページネーションのより高度なユースケースはネストされたページネーションです。これは、ページネーションを他の動的ルーティングパラメータと組み合わせたものです。ネストされたページネーションを使用すると、ページネーションされたコレクションを何らかのプロパティやタグでグループ化できます。
たとえば、ページネーションされたMarkdownの投稿を何らかのタグでグループ化したい場合、以下のURLにマッチする/src/pages/[tag]/[page].astroページを作成してネストされたページネーションを使用します。
/red/1(tag=red)/red/2(tag=red)/blue/1(tag=blue)/green/1(tag=green)
ネストされたページネーションは、paginate()の結果をグループごとに配列としてgetStaticPaths()から返すことで動作します。
以下の例では、上記のURLを作成するために、ネストされたページネーションを実装しています。
---import type { GetStaticPaths } from "astro";
export const 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: any) => post.frontmatter.tag === tag, ); return paginate(filteredPosts, { params: { tag }, pageSize: 10, }); });}) satisfies GetStaticPaths;
const { page } = Astro.props;const params = Astro.params;---ページの除外
Section titled “ページの除外”アンダースコア(_)を接頭辞としてファイル名に付けることで、ページやディレクトリをビルドから除外できます。アンダースコアで始まるファイルはルーターによって認識されず、dist/ディレクトリにも配置されません。
これを使用すると、一時的にページを無効にしたり、テストやユーティリティ、コンポーネントを関連するページと同じフォルダーに配置したりできます。
以下の例では、src/pages/index.astroとsrc/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
高度なルーティング
Section titled “高度なルーティング”
追加:
astro@7.0.0
デフォルトでは、Astroは組み込みパイプラインを使用してすべてのリクエストを処理します。このパイプラインでは、末尾のスラッシュの正規化、リダイレクト、セッション、アクション、ユーザーミドルウェア、ページのレンダリング、i18n、キャッシュの順にハンドラーが実行されます。一般的なルーティングやリクエスト処理のユースケースに対応するよう設計されていますが、すべてのプロジェクトに適しているとは限りません。
Astroの高度なルーティングを使用すると、このパイプラインを独自のものに置き換えられます。使用する組み込み機能とその実行位置を選択でき、パイプライン内の任意の場所に独自のロジックも追加できます。これにより、Astroが受信したリクエストを処理する方法を完全に制御できます。
カスタムエントリーポイントを作成する
Section titled “カスタムエントリーポイントを作成する”デフォルトのパイプラインが要件に合わない場合は、fetch()メソッドをもつオブジェクトをデフォルトエクスポートするsrc/fetch.tsファイルを作成して上書きできます。このメソッドは標準のRequestを受け取り、Responseを返す必要があります。
import type { Fetchable } from 'astro';
export default { async fetch(request) { // 独自のリクエスト処理ロジックをここに記述します return new Response("高度なルーティングからこんにちは!"); }} satisfies Fetchable;Astroの高度なルーティングのエントリーポイントでは、.ts、.js、.mjs、.mtsのファイル形式を使用できます。ほとんどの場合は.jsを、TypeScriptのサポートが必要な場合は.tsを使用することをおすすめします。
エントリーポイントのファイル名を変更する
Section titled “エントリーポイントのファイル名を変更する”デフォルトでは、Astroは高度なルーティングのエントリーポイントとしてsrc/fetch.tsを探します。ファイル名を変更するには、Astro設定ファイルでfetchFile (EN)オプションを設定します。
以下の例では、Astroにsrc/fetch.tsではなくsrc/handler.tsを探すよう指定します。
import { defineConfig } from 'astro/config';
export default defineConfig({ fetchFile: 'handler',});エントリーポイントを完全に無効にするには、fetchFileをnullに設定します。これは、別の目的でsrc/fetch.tsファイルをすでに使用している場合に便利です。
import { defineConfig } from 'astro/config';
export default defineConfig({ fetchFile: null,});独自のロジックを追加する
Section titled “独自のロジックを追加する”高度なルーティングの主な利点は、リクエストパイプラインに独自のロジックを挿入できることです。Astroがリクエストを処理する前、パイプラインのステージ間、またはレスポンスの生成後にコードを実行できます。
これには2つの方法があります。
astro()ハンドラー (EN)を使用して組み込みパイプライン全体を実行し、その前後にロジックを追加します。astro/fetch(EN)またはastro/hono(EN)の個別のハンドラーを組み合わせ、実行順序をより細かく制御します。
astro()でパイプライン全体を実行する
Section titled “astro()でパイプライン全体を実行する”Astroの組み込みルーティングの動作を維持しながら、その前後に独自のロジックを追加するには、astro() (EN)を使用します。この方法ではデフォルトのパイプライン順序を維持しつつ、前処理と後処理を1か所に追加できます。リクエストのログ記録やカスタムヘッダーの追加など、多くのユースケースではastro()だけで十分です。
以下の例では、Astroのパイプラインを実行する前に受信した各リクエストをログへ記録し、Astroの処理完了後にレスポンスへカスタムヘッダーを追加します。
import { FetchState, astro } from 'astro/fetch';
export default { async fetch(request: Request): Promise<Response> { const state = new FetchState(request);
// Astroのハンドラーを実行する前の独自の前処理 console.log(`${request.method} ${new URL(request.url).pathname}`);
const response = await astro(state);
// Astroのレンダリング後に実行する独自の後処理 response.headers.set('X-Powered-By', 'Astro'); return response; },};受信したリクエストのパス名と、Astroが内部でマッチさせるルーティングが同じであるとは限りません。そのため、url.pathname.startsWith('/dashboard')のようなチェックは回避される可能性があります。
リクエストのパス名を文字列と比較する前処理を、リクエストの認可に使用しないでください。ルーティングを保護するには、Honoなど、ルーティングのマッチングを担うルーターを使用してください。
個別のハンドラーを組み合わせる
Section titled “個別のハンドラーを組み合わせる”パイプラインの実行順序をより細かく制御したり、一部の機能を省略したりする場合は、astro/fetch (EN)の個別のハンドラー関数を組み合わせられます。各ハンドラーは、マッチしたルーティング、Cookie、セッションなど、リクエストごとのデータを追跡するFetchStateオブジェクト (EN)を操作します。ハンドラーは任意の順序で呼び出せ、その間に独自のロジックを挿入できます。
以下の例では、プロジェクトで使用するハンドラーだけを実行し、アクションの後かつページのレンダリング前に独自のロジックを追加します。
import { FetchState, actions, middleware, pages, i18n,} from 'astro/fetch';
export default { async fetch(request: Request): Promise<Response> { const state = new FetchState(request);
const actionResponse = await actions(state); if (actionResponse) return actionResponse;
// アクションとページレンダリングの間に実行する独自のロジック console.log(`Rendering ${new URL(request.url).pathname}`);
const response = await middleware(state, (s) => pages(s)); return i18n(state, response); },};Honoとともに使用する
Section titled “Honoとともに使用する”Astroは、astro/hono (EN)を介して、すべてのハンドラー関数にHono互換のラッパーも提供します。ルーティングフレームワークとしてHonoを使用する場合は、src/fetch.tsからHonoアプリをエクスポートできます。
import { Hono } from 'hono';import { logger } from 'hono/logger';import { actions, middleware, pages, i18n } from 'astro/hono';
const app = new Hono();
// Honoミドルウェアapp.use(logger());
// Astroのハンドラー(Honoミドルウェアとして使用)app.use(actions());app.use(middleware());app.use(pages());app.use(i18n());
export default app;保護したいHonoのルーティングに認可チェックを登録することもできます。
import { Hono } from 'hono';import { actions, middleware, pages, i18n } from 'astro/hono';import { isLoggedIn } from './lib/auth';
const app = new Hono();
// /dashboard配下のすべてのルーティングを保護します。app.use('/dashboard', requireAuth);app.use('/dashboard/*', requireAuth);
app.use(actions());app.use(middleware());app.use(pages());app.use(i18n());
export default app;
async function requireAuth(c, next) { if (!(await isLoggedIn(c.req.raw))) { return c.redirect('/login'); } return next();}