リダイレクト

リダイレクトを使用すると、受信したリクエストパスを別の宛先パスに転送できます。

リダイレクトを使用するには、next.config.jsredirectsキーを使用します:

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

redirectsは非同期関数で、sourcedestinationpermanentプロパティを持つオブジェクトの配列を返す必要があります:

  • source:受信リクエストのパスパターン
  • destination:ルーティングしたいパス
  • permanenttrueまたはfalse - trueの場合、クライアント/検索エンジンにリダイレクトを永久にキャッシュするよう指示する308ステータスコードが使用されます。falseの場合、一時的でキャッシュされない307ステータスコードが使用されます。

Next.jsが307と308を使用する理由:従来、一時的なリダイレクトには302、恒久的なリダイレクトには301が使用されていましたが、多くのブラウザは元のメソッドに関係なくリダイレクトのリクエストメソッドをGETに変更していました。例えば、ブラウザがPOST /v1/usersにリクエストを送信し、ステータスコード302とロケーション/v2/usersが返された場合、後続のリクエストは期待されるPOST /v2/usersではなくGET /v2/usersになる可能性があります。Next.jsはリクエストメソッドを明示的に保持するために307(一時的)と308(恒久的)のステータスコードを使用します。

  • basePathfalseまたはundefined - falseの場合、マッチング時にbasePathが含まれません。外部リダイレクトのみに使用できます。
  • localefalseまたはundefined - マッチング時にロケールを含めるかどうか。
  • hashasオブジェクトの配列で、typekeyvalueプロパティを持ちます。
  • missingmissingオブジェクトの配列で、typekeyvalueプロパティを持ちます。

リダイレクトは、ページや/publicファイルを含むファイルシステムよりも前にチェックされます。

Pages Routerを使用する場合、リダイレクトはクライアントサイドルーティング(Linkrouter.push)には適用されません(Middlewareが存在し、パスにマッチする場合を除く)。

リダイレクトが適用されるとき、リクエストで提供されたクエリ値はリダイレクト先に引き継がれます。例えば、次のリダイレクト設定を参照してください:

{
  source: '/old-blog/:path*',
  destination: '/blog/:path*',
  permanent: false
}

知っておくと便利sourcedestinationのパスパラメータでコロン:の前にスラッシュ/を含めることを忘れないでください。含めない場合、パスはリテラル文字列として扱われ、無限リダイレクトが発生するリスクがあります。

/old-blog/post-1?hello=worldがリクエストされると、クライアントは/blog/post-1?hello=worldにリダイレクトされます。

パスマッチング

パスマッチングが可能です。例えば/old-blog/:slug/old-blog/hello-worldにマッチします(ネストしたパスは不可):

next.config.js
module.exports = {
  async redirects() {
    return [
      {
        source: '/old-blog/:slug',
        destination: '/news/:slug', // マッチしたパラメータは宛先で使用可能
        permanent: true,
      },
    ]
  },
}

ワイルドカードパスマッチング

ワイルドカードパスにマッチさせるには、パラメータの後に*を使用します。例えば/blog/:slug*/blog/a/b/c/d/hello-worldにマッチします:

next.config.js
module.exports = {
  async redirects() {
    return [
      {
        source: '/blog/:slug*',
        destination: '/news/:slug*', // マッチしたパラメータは宛先で使用可能
        permanent: true,
      },
    ]
  },
}

正規表現パスマッチング

正規表現でパスにマッチさせるには、パラメータの後に正規表現を括弧で囲みます。例えば/post/:slug(\\d{1,})/post/123にマッチしますが、/post/abcにはマッチしません:

next.config.js
module.exports = {
  async redirects() {
    return [
      {
        source: '/post/:slug(\\d{1,})',
        destination: '/news/:slug', // マッチしたパラメータは宛先で使用可能
        permanent: false,
      },
    ]
  },
}

以下の文字(){}:*+?は正規表現パスマッチングに使用されるため、sourceで特殊値として使用されない場合は、前に\\を付けてエスケープする必要があります:

next.config.js
module.exports = {
  async redirects() {
    return [
      {
        // これは`/english(default)/something`がリクエストされた場合にマッチします
        source: '/english\\(default\\)/:slug',
        destination: '/en-us/:slug',
        permanent: false,
      },
    ]
  },
}

ヘッダー、クッキー、クエリのマッチング

リダイレクトをヘッダー、クッキー、またはクエリ値が一致した場合にのみ適用するには、hasフィールドを使用します。または一致しない場合に適用するにはmissingフィールドを使用します。リダイレクトが適用されるためには、sourceとすべてのhasアイテムが一致し、すべてのmissingアイテムが一致しない必要があります。

hasmissingアイテムは以下のフィールドを持ちます:

  • typeString - headercookiehostqueryのいずれかでなければなりません。
  • keyString - マッチング対象の選択されたタイプのキー。
  • valueStringまたはundefined - チェックする値。undefinedの場合、任意の値がマッチします。正規表現のような文字列を使用して値の特定の部分をキャプチャできます。例えば、first-(?<paramName>.*)という値がfirst-secondに使用された場合、secondは宛先で:paramNameとして使用可能です。
next.config.js
module.exports = {
  async redirects() {
    return [
      // ヘッダー`x-redirect-me`が存在する場合、
      // このリダイレクトが適用されます
      {
        source: '/:path((?!another-page$).*)',
        has: [
          {
            type: 'header',
            key: 'x-redirect-me',
          },
        ],
        permanent: false,
        destination: '/another-page',
      },
      // ヘッダー`x-dont-redirect`が存在する場合、
      // このリダイレクトは適用されません
      {
        source: '/:path((?!another-page$).*)',
        missing: [
          {
            type: 'header',
            key: 'x-do-not-redirect',
          },
        ],
        permanent: false,
        destination: '/another-page',
      },
      // ソース、クエリ、クッキーが一致する場合、
      // このリダイレクトが適用されます
      {
        source: '/specific/:path*',
        has: [
          {
            type: 'query',
            key: 'page',
            // 値が提供され、名前付きキャプチャグループ(例:(?<page>home))が
            // 使用されていないため、page値は宛先で利用できません
            value: 'home',
          },
          {
            type: 'cookie',
            key: 'authorized',
            value: 'true',
          },
        ],
        permanent: false,
        destination: '/another/:path*',
      },
      // ヘッダー`x-authorized`が存在し、
      // 一致する値が含まれている場合、このリダイレクトが適用されます
      {
        source: '/',
        has: [
          {
            type: 'header',
            key: 'x-authorized',
            value: '(?<authorized>yes|true)',
          },
        ],
        permanent: false,
        destination: '/home?authorized=:authorized',
      },
      // ホストが`example.com`の場合、
      // このリダイレクトが適用されます
      {
        source: '/:path((?!another-page$).*)',
        has: [
          {
            type: 'host',
            value: 'example.com',
          },
        ],
        permanent: false,
        destination: '/another-page',
      },
    ]
  },
}

basePathをサポートしたリダイレクト

basePathサポートをリダイレクトで利用する場合、各sourcedestinationには自動的にbasePathがプレフィックスとして追加されます(リダイレクトにbasePath: falseを追加しない限り):

next.config.js
module.exports = {
  basePath: '/docs',

  async redirects() {
    return [
      {
        source: '/with-basePath', // 自動的に/docs/with-basePathになる
        destination: '/another', // 自動的に/docs/anotherになる
        permanent: false,
      },
      {
        // basePath: falseが設定されているため/docsは追加されない
        source: '/without-basePath',
        destination: 'https://example.com',
        basePath: false,
        permanent: false,
      },
    ]
  },
}

i18nをサポートしたリダイレクト

i18nサポートをリダイレクトで利用する場合、各sourcedestinationには設定されたlocalesを処理するために自動的にプレフィックスが追加されます(リダイレクトにlocale: falseを追加しない限り)。locale: falseを使用する場合、sourcedestinationにロケールをプレフィックスとして付ける必要があります。

next.config.js
module.exports = {
  i18n: {
    locales: ['en', 'fr', 'de'],
    defaultLocale: 'en',
  },

  async redirects() {
    return [
      {
        source: '/with-locale', // すべてのロケールを自動的に処理
        destination: '/another', // ロケールを自動的に引き継ぐ
        permanent: false,
      },
      {
        // locale: falseが設定されているためロケールを自動処理しない
        source: '/nl/with-locale-manual',
        destination: '/nl/another',
        locale: false,
        permanent: false,
      },
      {
        // `en`がdefaultLocaleなので'/'にマッチ
        source: '/en',
        destination: '/en/another',
        locale: false,
        permanent: false,
      },
      // locale: falseが設定されていてもすべてのロケールにマッチ可能
      {
        source: '/:locale/page',
        destination: '/en/newpage',
        permanent: false,
        locale: false,
      },
      {
        // /(en|fr|de)/(.*)に変換されるため、/:path*のように
        // トップレベルの`/`や`/fr`ルートにはマッチしない
        source: '/(.*)',
        destination: '/another',
        permanent: false,
      },
    ]
  },
}

まれなケースとして、古いHTTPクライアントが適切にリダイレクトするためにカスタムステータスコードを割り当てる必要がある場合があります。このような場合、permanentプロパティの代わりにstatusCodeプロパティを使用できますが、両方は使用できません。IE11との互換性を確保するために、308ステータスコードには自動的にRefreshヘッダーが追加されます。

その他のリダイレクト

バージョン履歴

バージョン変更点
v13.3.0missingを追加。
v10.2.0hasを追加。
v9.5.0redirectsを追加。