跳至內容

重寫 (rewrites)

重寫允許您將傳入的請求路徑映射到不同的目標路徑。

重寫的功能類似於網址代理,並會遮罩目標路徑,讓使用者看起來像是沒有改變網站上的位置。 相反地,重新導向會重新導向到新的頁面,並顯示網址的變化。

要使用重寫功能,您可以在 `next.config.js` 中使用 `rewrites` 鍵。

next.config.js
module.exports = {
  async rewrites() {
    return [
      {
        source: '/about',
        destination: '/',
      },
    ]
  },
}

重寫規則會應用於客戶端路由,以上述例子來說,<Link href="/about"> 會套用重寫規則。

rewrites 是一個非同步函式,它預期會返回一個陣列或一個陣列物件(如下所示),其中包含具有 sourcedestination 屬性的物件。

  • sourceString - 是傳入的請求路徑模式。
  • destinationString - 是您要路由到的路徑。
  • basePathfalseundefined - 如果為 false,則在比對時不會包含 basePath,僅可用於外部重寫。
  • localefalseundefined - 是否在比對時不包含語系。
  • has 是一個 has 物件 陣列,具有 typekeyvalue 屬性。
  • missing 是一個 missing 物件 陣列,具有 typekeyvalue 屬性。

rewrites 函式返回一個陣列時,重寫規則會在檢查檔案系統(頁面和 /public 檔案)之後以及動態路由之前應用。當 rewrites 函式返回一個具有特定形狀的陣列物件時,可以更改此行為並進行更精細的控制,這從 Next.js 的 v10.1 版本開始。

next.config.js
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*`,
        },
      ],
    }
  },
}

注意事項beforeFiles 中的重寫規則在匹配來源後不會立即檢查檔案系統/動態路由,它們會繼續執行,直到所有 beforeFiles 都已檢查完畢。

Next.js 路由的檢查順序如下:

  1. 檢查/套用 標頭 (headers)
  2. 檢查/套用 重新導向 (redirects)
  3. 檢查/套用 beforeFiles 重寫規則。
  4. 檢查/提供來自 public 目錄 的靜態檔案、_next/static 檔案和非動態頁面。
  5. 檢查/套用 afterFiles 重寫規則,如果其中一個重寫規則匹配,則在每次匹配後檢查動態路由/靜態檔案。
  6. 檢查/套用 fallback 重寫規則,這些規則會在渲染 404 頁面之前以及在檢查動態路由/所有靜態資源之後應用。如果您在 getStaticPaths 中使用 fallback: true/'blocking',則您的 next.config.js 中定義的 fallback rewrites 將*不會*執行。

重寫參數

在重寫中使用參數時,如果 destination 中未使用任何參數,則參數會預設在查詢中傳遞。

next.config.js
module.exports = {
  async rewrites() {
    return [
      {
        source: '/old-about/:path*',
        destination: '/about', // The :path parameter isn't used here so will be automatically passed in the query
      },
    ]
  },
}

如果在 destination 中使用了參數,則不會自動在查詢中傳遞任何參數。

next.config.js
module.exports = {
  async rewrites() {
    return [
      {
        source: '/docs/:path*',
        destination: '/:path*', // The :path parameter is used here so will not be automatically passed in the query
      },
    ]
  },
}

如果在 destination 中已使用一個參數,您仍然可以透過在 destination 中指定查詢,手動在查詢中傳遞參數。

next.config.js
module.exports = {
  async rewrites() {
    return [
      {
        source: '/:first/:second',
        destination: '/:first?second=:second',
        // Since the :first parameter is used in the destination the :second parameter
        // will not automatically be added in the query although we can manually add it
        // as shown above
      },
    ]
  },
}

注意事項:來自自動靜態優化的靜態頁面或來自重新導向的預渲染參數將在 hydration 後於客戶端上解析,並在查詢中提供。

路徑匹配

允許路徑匹配,例如 /blog/:slug 將匹配 /blog/hello-world(不支援巢狀路徑)

next.config.js
module.exports = {
  async rewrites() {
    return [
      {
        source: '/blog/:slug',
        destination: '/news/:slug', // Matched parameters can be used in the destination
      },
    ]
  },
}

萬用字元路徑匹配

要匹配萬用字元路徑,您可以在參數後使用 *,例如 /blog/:slug* 將匹配 /blog/a/b/c/d/hello-world

next.config.js
module.exports = {
  async rewrites() {
    return [
      {
        source: '/blog/:slug*',
        destination: '/news/:slug*', // Matched parameters can be used in the destination
      },
    ]
  },
}

正規表達式路徑匹配
next.config.js
module.exports = {
  async rewrites() {
    return [
      {
        source: '/old-blog/:post(\\d{1,})',
        destination: '/blog/:post', // Matched parameters can be used in the destination
      },
    ]
  },
}

以下字元 (){}[]|\^.:*+-?$ 用於正規表達式路徑匹配,因此當在 source 中用作非特殊值時,必須在其前面加上 \\ 來進行跳脫。

next.config.js
module.exports = {
  async rewrites() {
    return [
      {
        // this will match `/english(default)/something` being requested
        source: '/english\\(default\\)/:slug',
        destination: '/en-us/:slug',
      },
    ]
  },
}

若要僅在標頭、Cookie 或查詢值也符合 has 欄位或不符合 missing 欄位時才匹配重新導向,可以使用這兩個欄位。 source 和所有 has 項目都必須匹配,且所有 missing 項目都必須不匹配,重新導向才會套用。

hasmissing 項目可以包含以下欄位:

  • typeString - 必須是 headercookiehostquery 其中之一。
  • keyString - 要匹配的所選類型的鍵值。
  • valueStringundefined - 要檢查的值,如果未定義,則任何值都將匹配。可以使用類似正規表達式的字串來擷取值的特定部分,例如,如果值 first-(?<paramName>.*) 用於 first-second,則 second 將可在目的地中使用 :paramName
next.config.js
module.exports = {
  async rewrites() {
    return [
      // if the header `x-rewrite-me` is present,
      // this rewrite will be applied
      {
        source: '/:path*',
        has: [
          {
            type: 'header',
            key: 'x-rewrite-me',
          },
        ],
        destination: '/another-page',
      },
      // if the header `x-rewrite-me` is not present,
      // this rewrite will be applied
      {
        source: '/:path*',
        missing: [
          {
            type: 'header',
            key: 'x-rewrite-me',
          },
        ],
        destination: '/another-page',
      },
      // if the source, query, and cookie are matched,
      // this rewrite will be applied
      {
        source: '/specific/:path*',
        has: [
          {
            type: 'query',
            key: 'page',
            // the page value will not be available in the
            // destination since value is provided and doesn't
            // use a named capture group e.g. (?<page>home)
            value: 'home',
          },
          {
            type: 'cookie',
            key: 'authorized',
            value: 'true',
          },
        ],
        destination: '/:path*/home',
      },
      // if the header `x-authorized` is present and
      // contains a matching value, this rewrite will be applied
      {
        source: '/:path*',
        has: [
          {
            type: 'header',
            key: 'x-authorized',
            value: '(?<authorized>yes|true)',
          },
        ],
        destination: '/home?authorized=:authorized',
      },
      // if the host is `example.com`,
      // this rewrite will be applied
      {
        source: '/:path*',
        has: [
          {
            type: 'host',
            value: 'example.com',
          },
        ],
        destination: '/another-page',
      },
    ]
  },
}

重新導向至外部連結

範例

重新導向允許您將請求重新導向至外部連結。這對於逐步採用 Next.js 尤其有用。以下是一個將主應用程式 `/blog` 路徑重新導向至外部網站的重新導向範例。

next.config.js
module.exports = {
  async rewrites() {
    return [
      {
        source: '/blog',
        destination: 'https://example.com/blog',
      },
      {
        source: '/blog/:slug',
        destination: 'https://example.com/blog/:slug', // Matched parameters can be used in the destination
      },
    ]
  },
}

如果您使用的是 `trailingSlash: true`,您也需要在 `source` 參數中插入尾端斜線。如果目標伺服器也需要尾端斜線,則也應將其包含在 `destination` 參數中。

next.config.js
module.exports = {
  trailingSlash: true,
  async rewrites() {
    return [
      {
        source: '/blog/',
        destination: 'https://example.com/blog/',
      },
      {
        source: '/blog/:path*/',
        destination: 'https://example.com/blog/:path*/',
      },
    ]
  },
}

逐步採用 Next.js

您也可以讓 Next.js 在檢查所有 Next.js 路徑後,退回到代理現有網站。

這樣,當您將更多頁面遷移到 Next.js 時,就不必更改重新導向設定。

next.config.js
module.exports = {
  async rewrites() {
    return {
      fallback: [
        {
          source: '/:path*',
          destination: `https://custom-routes-proxying-endpoint.vercel.app/:path*`,
        },
      ],
    }
  },
}

支援 basePath 的重新導向

當利用`basePath` 支援搭配重新導向時,每個 `source` 和 `destination` 都會自動加上 `basePath` 前綴,除非您在重新導向中加入 `basePath: false`。

next.config.js
module.exports = {
  basePath: '/docs',
 
  async rewrites() {
    return [
      {
        source: '/with-basePath', // automatically becomes /docs/with-basePath
        destination: '/another', // automatically becomes /docs/another
      },
      {
        // does not add /docs to /without-basePath since basePath: false is set
        // Note: this can not be used for internal rewrites e.g. `destination: '/another'`
        source: '/without-basePath',
        destination: 'https://example.com',
        basePath: false,
      },
    ]
  },
}

支援 i18n 的重新導向 `i18n` 支援搭配重新導向時,每個 `source` 和 `destination` 都會自動加上前綴來處理設定的 `locales`,除非您在重新導向中加入 `locale: false`。如果使用了 `locale: false`,您必須在 `source` 和 `destination` 前面加上語系設定,才能正確匹配。

next.config.js
module.exports = {
  i18n: {
    locales: ['en', 'fr', 'de'],
    defaultLocale: 'en',
  },
 
  async rewrites() {
    return [
      {
        source: '/with-locale', // automatically handles all locales
        destination: '/another', // automatically passes the locale on
      },
      {
        // does not handle locales automatically since locale: false is set
        source: '/nl/with-locale-manual',
        destination: '/nl/another',
        locale: false,
      },
      {
        // this matches '/' since `en` is the defaultLocale
        source: '/en',
        destination: '/en/another',
        locale: false,
      },
      {
        // it's possible to match all locales even when locale: false is set
        source: '/:locale/api-alias/:path*',
        destination: '/api/:path*',
        locale: false,
      },
      {
        // this gets converted to /(en|fr|de)/(.*) so will not match the top-level
        // `/` or `/fr` routes like /:path* would
        source: '/(.*)',
        destination: '/another',
      },
    ]
  },
}

版本歷史

版本變更
v13.3.0新增 missing
v10.2.0新增 has
v9.5.0新增標題。