メインコンテンツまでスキップ

redirects

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

リダイレクトを使用するには、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 - 一致時にロケールを含みたくない場合
  • hastypekeyvalueプロパティを持つhasオブジェクトの配列です
  • missingtypekeyvalueプロパティを持つmissingオブジェクトの配列です

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

Pages Routerを使用する場合、Middlewareが存在してパスに一致しない限り、リダイレクトはクライアントサイドのルーティング(Linkrouter.push)には適用されません。

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

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

/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', // 一致したパラメータはdestinationで使用可能
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*', // 一致したパラメータはdestinationで使用可能
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', // 一致したパラメータはdestinationで使用可能
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 - チェックする値、未定義の場合は任意の値が一致します。特定の部分をキャプチャするために、正規表現のような文字列を使用できます。たとえば、値がfirst-(?<paramName>.*)の場合、first-secondは、:paramNameを使用してdestinationでsecondを利用できます。
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、query、cookieが一致する場合、
// このリダイレクトが適用されます
{
source: '/specific/:path*',
has: [
{
type: 'query',
key: 'page',
// pageの値は、値が提供されており、
// 名前付きキャプチャグループを使用しないため、
// destinationでは利用できません
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サポートを活用すると、それぞれのsourcedestinationbasePathで自動的に接頭辞が付けられます。ただし、リダイレクトに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`であるため、'/'にマッチします
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が追加されました