Переопределения (rewrites)
Правила перезаписи (rewrites) позволяют сопоставить входящий путь запроса с другим целевым путем.
Перезаписи действуют как прокси URL и маскируют целевой путь, создавая впечатление, что пользователь не изменил свое местоположение на сайте. В отличие от этого, редиректы перенаправляют на новую страницу и показывают изменения URL.
Для использования перезаписей вы можете использовать ключ rewrites
в next.config.js
:
module.exports = {
async rewrites() {
return [
{
source: '/about',
destination: '/',
},
]
},
}
Перезаписи применяются к клиентской маршрутизации, <Link href="/about">
будет применять перезапись в примере выше.
rewrites
— это асинхронная функция, которая ожидает возврата либо массива, либо объекта с массивами (см. ниже), содержащими объекты со свойствами source
и destination
:
source
:String
— шаблон входящего пути запроса.destination
:String
— путь, на который нужно перенаправить.basePath
:false
илиundefined
— если false, basePath не будет включен при сопоставлении, может использоваться только для внешних перезаписей.locale
:false
илиundefined
— указывает, следует ли исключать локаль при сопоставлении.has
— массив объектов has со свойствамиtype
,key
иvalue
.missing
— массив объектов missing со свойствамиtype
,key
иvalue
.
Когда функция rewrites
возвращает массив, перезаписи применяются после проверки файловой системы (страницы и файлы /public
) и перед динамическими маршрутами. Когда функция rewrites
возвращает объект с массивами определенной структуры, это поведение можно изменить и более точно контролировать, начиная с версии v10.1
Next.js:
module.exports = {
async rewrites() {
return {
beforeFiles: [
// Эти перезаписи проверяются после headers/redirects
// и перед всеми файлами, включая _next/public файлы, что
// позволяет переопределять файлы страниц
{
source: '/some-page',
destination: '/somewhere-else',
has: [{ type: 'query', key: 'overrideMe' }],
},
],
afterFiles: [
// Эти перезаписи проверяются после проверки pages/public файлов
// но перед динамическими маршрутами
{
source: '/non-existent',
destination: '/somewhere-else',
},
],
fallback: [
// Эти перезаписи проверяются после проверки pages/public файлов
// и динамических маршрутов
{
source: '/:path*',
destination: `https://my-old-site.com/:path*`,
},
],
}
},
}
Важно: перезаписи в
beforeFiles
не проверяют файловую систему/динамические маршруты сразу после сопоставления источника, они продолжаются до проверки всехbeforeFiles
.
Порядок проверки маршрутов в Next.js:
- Проверяются/применяются headers
- Проверяются/применяются redirects
- Проверяются/применяются
beforeFiles
перезаписи - Проверяются/обслуживаются статические файлы из public directory, файлы
_next/static
и нединамические страницы - Проверяются/применяются
afterFiles
перезаписи, если одна из этих перезаписей совпадает, мы проверяем динамические маршруты/статические файлы после каждого совпадения - Проверяются/применяются
fallback
перезаписи, они применяются перед отображением страницы 404 и после проверки динамических маршрутов/всех статических ресурсов. Если вы используете fallback: true/'blocking' вgetStaticPaths
,fallback
перезаписи, определенные в вашемnext.config.js
, не будут выполнены.
Параметры перезаписи
При использовании параметров в перезаписи параметры по умолчанию передаются в запросе, если ни один из параметров не используется в destination
.
module.exports = {
async rewrites() {
return [
{
source: '/old-about/:path*',
destination: '/about', // Параметр :path не используется здесь, поэтому будет автоматически передан в запросе
},
]
},
}
Если параметр используется в destination, ни один из параметров не будет автоматически передан в запросе.
module.exports = {
async rewrites() {
return [
{
source: '/docs/:path*',
destination: '/:path*', // Параметр :path используется здесь, поэтому не будет автоматически передан в запросе
},
]
},
}
Вы все еще можете передать параметры вручную в запросе, если один уже используется в destination, указав запрос в destination
.
module.exports = {
async rewrites() {
return [
{
source: '/:first/:second',
destination: '/:first?second=:second',
// Поскольку параметр :first используется в destination, параметр :second
// не будет автоматически добавлен в запрос, хотя мы можем добавить его
// вручную, как показано выше
},
]
},
}
Важно: Параметры из Automatic Static Optimization или prerendering будут разобраны на клиенте после гидратации и предоставлены в запросе.
Сопоставление путей
Разрешено сопоставление путей, например /blog/:slug
совпадет с /blog/hello-world
(без вложенных путей):
module.exports = {
async rewrites() {
return [
{
source: '/blog/:slug',
destination: '/news/:slug', // Сопоставленные параметры могут использоваться в destination
},
]
},
}
Сопоставление путей с подстановочными знаками
Для сопоставления пути с подстановочным знаком можно использовать *
после параметра, например /blog/:slug*
совпадет с /blog/a/b/c/d/hello-world
:
module.exports = {
async rewrites() {
return [
{
source: '/blog/:slug*',
destination: '/news/:slug*', // Сопоставленные параметры могут использоваться в destination
},
]
},
}
Сопоставление путей с регулярными выражениями
Для сопоставления пути с регулярным выражением можно обернуть регулярное выражение в скобки после параметра, например /blog/:slug(\\d{1,})
совпадет с /blog/123
, но не с /blog/abc
:
module.exports = {
async rewrites() {
return [
{
source: '/old-blog/:post(\\d{1,})',
destination: '/blog/:post', // Сопоставленные параметры могут использоваться в destination
},
]
},
}
Следующие символы (
, )
, {
, }
, :
, *
, +
, ?
используются для сопоставления путей с регулярными выражениями, поэтому при использовании в source
как обычные значения они должны быть экранированы с помощью \\
перед ними:
module.exports = {
async rewrites() {
return [
{
// это совпадет с запросом `/english(default)/something`
source: '/english\\(default\\)/:slug',
destination: '/en-us/:slug',
},
]
},
}
Сопоставление заголовков, куки и запросов
Чтобы перезапись применялась только при совпадении значений заголовков, куки или запросов, можно использовать поле has
или missing
. И source
, и все элементы has
должны совпадать, а все элементы missing
не должны совпадать для применения перезаписи.
Элементы has
и missing
могут иметь следующие поля:
type
:String
— должно быть либоheader
,cookie
,host
, илиquery
.key
:String
— ключ из выбранного типа для сопоставления.value
:String
илиundefined
— значение для проверки, если undefined, подойдет любое значение. Можно использовать строку, похожую на регулярное выражение, для захвата определенной части значения, например, если значениеfirst-(?<paramName>.*)
используется дляfirst-second
, тоsecond
можно будет использовать в destination как:paramName
.
module.exports = {
async rewrites() {
return [
// если заголовок `x-rewrite-me` присутствует,
// эта перезапись будет применена
{
source: '/:path*',
has: [
{
type: 'header',
key: 'x-rewrite-me',
},
],
destination: '/another-page',
},
// если заголовок `x-rewrite-me` отсутствует,
// эта перезапись будет применена
{
source: '/:path*',
missing: [
{
type: 'header',
key: 'x-rewrite-me',
},
],
destination: '/another-page',
},
// если совпадают source, query и cookie,
// эта перезапись будет применена
{
source: '/specific/:path*',
has: [
{
type: 'query',
key: 'page',
// значение page не будет доступно в destination,
// так как value предоставлено и не использует именованную группу захвата, например (?<page>home)
value: 'home',
},
{
type: 'cookie',
key: 'authorized',
value: 'true',
},
],
destination: '/:path*/home',
},
// если заголовок `x-authorized` присутствует и
// содержит соответствующее значение, эта перезапись будет применена
{
source: '/:path*',
has: [
{
type: 'header',
key: 'x-authorized',
value: '(?<authorized>yes|true)',
},
],
destination: '/home?authorized=:authorized',
},
// если хост `example.com`,
// эта перезапись будет применена
{
source: '/:path*',
has: [
{
type: 'host',
value: 'example.com',
},
],
destination: '/another-page',
},
]
},
}
Перезапись на внешний URL
Перезаписи позволяют перенаправлять на внешний URL. Это особенно полезно для постепенного внедрения Next.js. Ниже приведен пример перезаписи для перенаправления маршрута /blog
вашего основного приложения на внешний сайт.
module.exports = {
async rewrites() {
return [
{
source: '/blog',
destination: 'https://example.com/blog',
},
{
source: '/blog/:slug',
destination: 'https://example.com/blog/:slug', // Сопоставленные параметры могут использоваться в destination
},
]
},
}
Если вы используете trailingSlash: true
, вам также нужно добавить завершающий слеш в параметр source
. Если сервер назначения также ожидает завершающий слеш, он должен быть включен в параметр destination
.
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.
module.exports = {
async rewrites() {
return {
fallback: [
{
source: '/:path*',
destination: `https://custom-routes-proxying-endpoint.vercel.app/:path*`,
},
],
}
},
}
Перезаписи с поддержкой basePath
При использовании basePath
с перезаписями каждый source
и destination
автоматически дополняется basePath
, если вы не добавите basePath: false
к перезаписи:
module.exports = {
basePath: '/docs',
async rewrites() {
return [
{
source: '/with-basePath', // автоматически становится /docs/with-basePath
destination: '/another', // автоматически становится /docs/another
},
{
// не добавляет /docs к /without-basePath, так как установлено basePath: false
// Примечание: это нельзя использовать для внутренних перезаписей, например `destination: '/another'`
source: '/without-basePath',
destination: 'https://example.com',
basePath: false,
},
]
},
}
Перезаписи с поддержкой i18n
При использовании i18n
с перезаписями каждый source
и destination
автоматически дополняется для обработки настроенных locales
, если вы не добавите locale: false
к перезаписи. Если используется locale: false
, вы должны добавить локаль в начало source
и destination
для правильного сопоставления.
module.exports = {
i18n: {
locales: ['en', 'fr', 'de'],
defaultLocale: 'en',
},
async rewrites() {
return [
{
source: '/with-locale', // автоматически обрабатывает все локали
destination: '/another', // автоматически передает локаль
},
{
// не обрабатывает локали автоматически, так как установлено locale: false
source: '/nl/with-locale-manual',
destination: '/nl/another',
locale: false,
},
{
// это соответствует '/', так как `en` является defaultLocale
source: '/en',
destination: '/en/another',
locale: false,
},
{
// можно сопоставить все локали, даже если установлено locale: false
source: '/:locale/api-alias/:path*',
destination: '/api/:path*',
locale: false,
},
{
// это преобразуется в /(en|fr|de)/(.*), поэтому не будет соответствовать
// корневому `/` или `/fr`, как это сделал бы /:path*
source: '/(.*)',
destination: '/another',
},
]
},
}
История версий
Версия | Изменения |
---|---|
v13.3.0 | Добавлен missing . |
v10.2.0 | Добавлен has . |
v9.5.0 | Добавлены заголовки. |