Proxy:rewrite
TL;DR
next.config.js: Rewrites | Next.js
- 和 Redirects 不同,使用 rewrite 作為 URL 代理可以隱藏目標路徑。
rewrites
是一個異步函數,它預期 return 一個 array。這個 array 必須有包含source
和destination
屬性的 Object- 默認情況下,
rewrites
會在檢查完 filesystem(page 和/public
文件)之後,在動態路由產生之前被執行。但實際執行時機在 v10.1 版以後的 Next.js 可以用beforeFiles
、afterFiles
、和fallback
指定。
Next.js 檢查並建立路由的順序
- 確認 Headers的定義
- 確認
rewrites
的定義 - 確認
beforeFiles
的定義 - 確認
public/
和_next/static
等靜態頁面的結構和定義 - 確認
afterFiles
的定義- 如果其中有匹配的 rewrite,便會在每次匹配後檢查動態路由和靜態文件
- 在遇到找不到路徑、渲染 404 頁面之前,確認
fallback
的定義
語法
基本用法
module.exports = {
async rewrites() {
return [
{
source: '/about',
destination: '/',
},
]
},
}
指定 rewrite 時機寫法
module.exports = {
async rewrites() {
return {
beforeFiles: [
// These rewrites are checked after headers/redirects
// and before all files including _next/public files which
// allows overriding page files
{
source: '/some-page',
destination: '/somewhere-else',
has: [{ type: 'query', key: 'overrideMe' }],
},
],
afterFiles: [
// These rewrites are checked after pages/public files
// are checked but before dynamic routes
{
source: '/non-existent',
destination: '/somewhere-else',
},
],
fallback: [
// These rewrites are checked after both pages/public files
// and dynamic routes are checked
{
source: '/:path*',
destination: `https://my-old-site.com/:path*`,
},
],
}
},
}
參數
如果參數沒有被用在 destination
中,就會被自動以 query 的的形式傳送
module.exports = {
async rewrites() {
return [
{
source: '/old-about/:path*',
destination: '/about',
// 因為 :path 參數在 destination 中沒有被使用,所以會自動以 query 的的形式傳送
},
]
},
}
如果想要讓參數被用在 path 中,需要在 destination 中指定
module.exports = {
async rewrites() {
return [
{
source: '/docs/:path*',
destination: '/:path*',
},
]
},
}
兩個以上的參數時可能遇到參數丟失問題
當有兩個以上的參數時,就算只有一個被用在 path 中,剩餘的參數也不會被傳遞。 這時候我們需要明確指定剩餘參數的傳法:
module.exports = {
async rewrites() {
return [
{
source: '/:first/:second',
destination: '/:first?second=:second',
// 因為 :first 參數在destination 被使用,所以 :second 參數並不會被傳遞。
// 不過我們可以透過明確的指定讓參數不會丟失
},
]
},
}
路由配對
巢狀路由配對
支援巢狀路由配對
module.exports = {
async rewrites() {
return [
{
source: '/blog/:slug',
destination: '/news/:slug', // Matched parameters can be used in the destination
},
]
},
}
Wildcards
支援 Wildcards
module.exports = {
async rewrites() {
return [
{
source: '/blog/:slug*',
// 會匹配任何符合此 wildcard 的路徑,如 /blog/a/b/c/d/hello-world
destination: '/news/:slug*',
},
]
},
}
Regex
可以使用正則表達式進行路由配對
module.exports = {
async rewrites() {
return [
{
source: '/old-blog/:post(\\d{1,})',
destination: '/blog/:post',
},
]
},
}
特殊字元處理
由於(
, )
, {
, }
, :
, *
, +
, ?
等特殊字元在正則表達式中有特殊意涵,所以如果出現在 path 中時,需要使用 \\
作為區分
module.exports = {
async rewrites() {
return [
{
// 會匹配 `/english(default)/something`
source: '/english\\(default\\)/:slug',
destination: '/en-us/:slug',
},
]
},
}
Rewrite 到外部 link
支援 rewrite 重寫到外部 url
module.exports = {
async rewrites() {
return [
{
source: '/blog',
destination: 'https://example.com/blog',
},
{
source: '/blog/:slug',
destination: 'https://example.com/blog/:slug',
// 同樣支援外部 url 的路徑參數
},
]
},
}
Trailing Slash
如果外部 link 需要有一個 Trailing Slash,那麼
- 需要設定
trailingSlash: true
- 在
source
中指定 path 需要加入 trailing slash
module.exports = {
trailingSlash: true, // 這裡設定
async rewrites() {
return [
{
source: '/blog/', // 需要加上 trailing slash
destination: 'https://example.com/blog/',
},
{
source: '/blog/:path*/',
destination: 'https://example.com/blog/:path*/',
},
]
},
}
Base Path
在使用轉移到外部路由時,可以指定目標路徑的 base path,並在不需要使用的路由將其關閉
module.exports = {
basePath: '/docs',
async rewrites() {
return [
{
source: '/with-basePath', // 會自動變成 /docs/with-basePath
destination: '/another', // 會自動變成 /docs/another
},
{
// 不會自動加上 base path
// 針對內部路由的 rewrite 不能使用
source: '/without-basePath',
destination: 'https://example.com',
basePath: false,
},
]
},
}
其他沒整理的內容
個人使用場景
config.js
中api
的代用:local 開發想打 staging 環境 api,由於 Next 不支援直接修改 api 的寫法,所以用這個 proxy 代用