Astro Advanced Routing 怎麼用?用 src/fetch.ts 插入請求管線
Astro 7 新增的 Advanced Routing,不是另一個頁面檔名規則,而是讓你接管 Astro 處理每個 request 的入口。預設情況下,Astro 會依固定順序處理 trailing slash、redirect、session、actions、middleware、page、i18n 與 cache;當你需要在這條管線前後加入檢查或調整順序時,才適合使用 src/fetch.ts。
直接答案是:先用 src/fetch.ts 的 astro(state) 包住內建 pipeline,加入少量前置或後置邏輯;只有需要省略或重排內建 handler 時,才改用 astro/fetch 的個別 handler。升級 Astro 7 前還要確認專案沒有把 src/fetch.ts 當成一般工具檔。
先確認專案真的在 Astro 7 路徑
Advanced Routing 是 [email protected] 加入的功能,src/fetch.ts 在 v7 也成為保留檔名。先查看目前版本與是否已有同名檔案:
pnpm list astro --depth 0test -e src/fetch.ts && sed -n '1,220p' src/fetch.ts || truerg -n 'fetchFile|advancedRouting|experimental' astro.config.mjs package.json src如果專案仍是 Astro 5 或 6,不要只建立檔案就期待它有 v7 的 request pipeline 行為。可以先看 Astro 7 升級前的建置與設定檔清單,把 Node.js、Vite、Markdown plugin、adapter 和現有 src/fetch.ts 用途分開驗證。
最小做法:保留 Astro 內建 pipeline
多數需求只是加入 request logging、驗證某個 header、或在回應完成後補一個 header。這時使用 FetchState 和 astro(),不要自己重寫所有 handler:
import type { Fetchable } from 'astro'import { FetchState, astro } from 'astro/fetch'
export default { async fetch(request: Request): Promise<Response> { const state = new FetchState(request) const url = new URL(request.url)
if (url.pathname.startsWith('/admin/')) { console.log(`admin request: ${request.method} ${url.pathname}`) }
const response = await astro(state) response.headers.set('X-Route-Pipeline', 'astro') return response },} satisfies Fetchable這個結構保留 Astro 原本的路由順序,並把自訂邏輯放在 pipeline 前後。若要做登入或權限判斷,console.log 只是一個示範位置;實際上應使用已驗證的 session、token 或 adapter 提供的身份資訊,不要用未驗證的 cookie 字串當成授權結果。
什麼時候要拆開個別 handler
如果需求是「保留 actions 和 pages,但不要使用某個內建階段」,或「在 middleware 和 pages 中間插入自己的處理」,才需要從 astro/fetch 匯入個別 handler。官方示範的基本形狀如下:
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, (nextState) => pages(nextState)) return i18n(state, response) },}這種寫法的維護成本比 astro(state) 高,因為你現在要負責記住哪些 handler 被保留、先後順序和 response 是否已被處理。每次升級 Astro 都要重新對照官方 routing 文件,不要把目前看到的 handler 清單當成永久 API 順序。
如果團隊偏好 Hono,也可以從 astro/hono 使用相同概念的 wrapper,把 Hono middleware 和 Astro handlers 放在同一條 pipeline。這是選擇另一個路由組合方式,不代表 Hono 會自動替你處理 Astro 的 session、i18n 或 cache 設定。
src/fetch.ts 衝突時改名或停用
Astro 7 會自動尋找 src/fetch.ts、src/fetch.js、src/fetch.mjs 或 src/fetch.mts。如果原本就有同名檔案,Astro 可能把它當成 Advanced Routing 入口,造成與原本用途無關的錯誤。
可以在 astro.config.mjs 改用其他檔名:
import { defineConfig } from 'astro/config'
export default defineConfig({ fetchFile: 'handler',})如果專案不需要這個入口,也可以明確停用:
import { defineConfig } from 'astro/config'
export default defineConfig({ fetchFile: null,})改名與停用都應該和升級分開驗證。先確認 src/fetch.ts 是否被其他程式碼 import,再跑 pnpm check、pnpm build,最後用專案使用的 adapter 或部署環境測一條真正的 request。
上線前要驗證的不是只有 build
Advanced Routing 會改變 request-time 的入口,因此至少要測:
- 一般頁面、動態路由與不存在路徑的回應狀態。
- trailing slash、redirect、session、actions 和 middleware 是否仍依預期執行。
- 你新增的前置檢查是否會阻擋靜態資產、健康檢查或 webhook。
- response header、cache、cookie 和錯誤頁是否仍被 adapter 正確輸出。
- production build 後的 preview 或 staging request,而不是只在 dev server 點開首頁。
如果只想加一個 header 或記錄 URL,先用 astro(state)。只有測試能證明需要重排 pipeline 時,才把內建 handler 拆開;這樣升級時要追蹤的內部邊界比較少。
結論:從包裝內建流程開始
Astro Advanced Routing 的實用切入點是 src/fetch.ts 加上 FetchState 與 astro():先保留 Astro 已經處理好的流程,再把自訂檢查放在前後。當需求真的涉及省略或重排 handler,才使用個別 astro/fetch API;同時把保留檔名衝突、adapter request 和 build 後驗證列入 Astro 7 升級清單。
常見問題
Q: Astro 7 一定要自己建立 src/fetch.ts 嗎?
A: 不一定。src/fetch.ts 是 Advanced Routing 的預設入口,但只有需要自訂 request pipeline 時才要建立。若專案不需要這個功能,可以不建立,或在 astro.config.mjs 設定 fetchFile: null 明確停用。
Q: 我原本就有 src/fetch.ts,升級 Astro 7 會怎樣?
A: Astro 7 會把它視為 Advanced Routing 的特殊檔名,可能造成原本的工具檔被當成 route handler。升級前先確認用途,再用 fetchFile 指向其他檔案、停用入口,或把原檔改名並更新 import。
Q: 只想加 response header,也要自己呼叫所有 handler 嗎?
A: 不需要。用 FetchState 建立狀態、呼叫 astro(state) 取得原本的 response,接著修改 header 即可。自己組合 actions、middleware、pages 和 i18n 適合需要改變 pipeline 順序的情境,維護成本較高。
參考資料:
Astro Docs:Routing — Advanced routing
回報錯字、失效連結,或告訴我你想看的延伸主題。