Переопределения (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 | Добавлены заголовки. |