redirects
リダイレクトを使用すると、受信リクエストパスを別の宛先パスにリダイレクトできます。
リダイレクトを使用するには、next.config.js
でredirects
キーを使用します:
module.exports = {
async redirects() {
return [
{
source: '/about',
destination: '/',
permanent: true,
},
]
},
}
redirects
は非同期関数で、source
、destination
、permanent
プロパティを持つオブジェクトを保持する配列を返すことを期待しています:
source
は受信リクエストパスのパターンですdestination
はルートしたいパスですpermanent
はtrue
または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永久リダイレクトステータスコードを使用します。
basePath
:false
またはundefined
- falseの場合、basePath
は一致時に含まれません。外部リダイレクトにのみ使用できますlocale
:false
またはundefined
- 一致時にロケールを含みたくない場合has
はtype
、key
、value
プロパティを持つhasオブジェクトの配列ですmissing
はtype
、key
、value
プロパティを持つmissingオブジェクトの配列です
リダイレクトは、ファイルシステム(ページや/public
ファイルを含む)よりも先にチェックされます。
Pages Routerを使用する場合、Middlewareが存在してパスに一致しない限り、リダイレクトはクライアントサイドのルーティング(Link
、router.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
(ネストされたパスなし)にマッチします:
module.exports = {
async redirects() {
return [
{
source: '/old-blog/:slug',
destination: '/news/:slug', // 一致したパラメータはdestinationで使用可能
permanent: true,
},
]
},
}
ワイルドカードパスマッチング
ワイルドカードパスにマッチするには、パラメータの後に*
を使用します。たとえば、/blog/:slug*
は/blog/a/b/c/d/hello-world
にマッチします:
module.exports = {
async redirects() {
return [
{
source: '/blog/:slug*',
destination: '/news/:slug*', // 一致したパラメータはdestinationで使用可能
permanent: true,
},
]
},
}
正規表現パスマッチング
正規表現パスにマッチするには、パラメータの後ろに正規表現を括弧内にラップします。たとえば、/post/:slug(\\d{1,})
は/post/123
にマッチしますが、/post/abc
にはマッチしません:
module.exports = {
async redirects() {
return [
{
source: '/post/:slug(\\d{1,})',
destination: '/news/:slug', // 一致したパラメータはdestinationで使用可能
permanent: false,
},
]
},
}
次の文字(
、)
、{
、}
、:
、*
、+
、?
は正規表現パスマッチングに使用されるため、source
で非特殊値として使用する場合は、それらの前に\\
を追加してエスケープする必要があります:
module.exports = {
async redirects() {
return [
{
// これは`/english(default)/something`のリクエストにマッチします
source: '/english\\(default\\)/:slug',
destination: '/en-us/:slug',
permanent: false,
},
]
},
}
ヘッダー、クッキー、クエリのマッチング
ヘッダー、クッキー、またはクエリの値がhas
フィールドで一致する場合、またはmissing
フィールドで一致しない場合にのみ、リダイレクトを一致させることができます。source
とすべてのhas
項目が一致し、すべてのmissing
項目が一致しないときにのみリダイレクトが適用されます。
has
とmissing
項目は、次のフィールドを持つことができます:
type
:String
-header
、cookie
、host
、query
のいずれかでなければなりませんkey
:String
- 照合する選択したタイプからのキーvalue
:String
またはundefined
- チェックする値、未定義の場合は任意の値が一致します。特定の部分をキャプチャするために、正規表現のような文字列を使用できます。たとえば、値がfirst-(?<paramName>.*)
の場合、first-second
は、:paramName
を使用してdestinationでsecond
を利用できます。
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
サポートを活用すると、それぞれのsource
とdestination
がbasePath
で自動的に接頭辞が付けられます。ただし、リダイレクトにbasePath: false
を追加した場合は除きます:
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
サポートを活用すると、それぞれのsource
とdestination
が設定されたlocales
を処理するために自動的にプレフィックスが付けられます。ただし、リダイレクトにlocale: false
を追加した場合は除きます。locale: false
が使用される場合は、一致するためにsource
とdestination
にロケールをプレフィックスしなければなりません。
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
ヘッダーが追加されます。
その他のリダイレクト
- API RoutesやRoute Handlers内で、受信リクエストに基づいてリダイレクトを行うことができます
getStaticProps
やgetServerSideProps
内で、リクエスト時に特定のページをリダイレクトすることができます
バージョン履歴
バージョン | 変更点 |
---|---|
v13.3.0 | missing が追加されました |
v10.2.0 | has が追加されました |
v9.5.0 | redirects が追加されました |