Переопределения (rewrites)

Правила перезаписи (rewrites) позволяют сопоставить входящий путь запроса с другим целевым путем.

Перезаписи действуют как прокси URL и маскируют целевой путь, создавая впечатление, что пользователь не изменил свое местоположение на сайте. В отличие от этого, редиректы перенаправляют на новую страницу и показывают изменения URL.

Для использования перезаписей вы можете использовать ключ rewrites в next.config.js:

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:

next.config.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:

  1. Проверяются/применяются headers
  2. Проверяются/применяются redirects
  3. Проверяются/применяются beforeFiles перезаписи
  4. Проверяются/обслуживаются статические файлы из public directory, файлы _next/static и нединамические страницы
  5. Проверяются/применяются afterFiles перезаписи, если одна из этих перезаписей совпадает, мы проверяем динамические маршруты/статические файлы после каждого совпадения
  6. Проверяются/применяются fallback перезаписи, они применяются перед отображением страницы 404 и после проверки динамических маршрутов/всех статических ресурсов. Если вы используете fallback: true/'blocking' в getStaticPaths, fallback перезаписи, определенные в вашем next.config.js, не будут выполнены.

Параметры перезаписи

При использовании параметров в перезаписи параметры по умолчанию передаются в запросе, если ни один из параметров не используется в destination.

next.config.js
module.exports = {
  async rewrites() {
    return [
      {
        source: '/old-about/:path*',
        destination: '/about', // Параметр :path не используется здесь, поэтому будет автоматически передан в запросе
      },
    ]
  },
}

Если параметр используется в destination, ни один из параметров не будет автоматически передан в запросе.

next.config.js
module.exports = {
  async rewrites() {
    return [
      {
        source: '/docs/:path*',
        destination: '/:path*', // Параметр :path используется здесь, поэтому не будет автоматически передан в запросе
      },
    ]
  },
}

Вы все еще можете передать параметры вручную в запросе, если один уже используется в destination, указав запрос в destination.

next.config.js
module.exports = {
  async rewrites() {
    return [
      {
        source: '/:first/:second',
        destination: '/:first?second=:second',
        // Поскольку параметр :first используется в destination, параметр :second
        // не будет автоматически добавлен в запрос, хотя мы можем добавить его
        // вручную, как показано выше
      },
    ]
  },
}

Важно: Параметры из Automatic Static Optimization или prerendering будут разобраны на клиенте после гидратации и предоставлены в запросе.

Сопоставление путей

Разрешено сопоставление путей, например /blog/:slug совпадет с /blog/hello-world (без вложенных путей):

next.config.js
module.exports = {
  async rewrites() {
    return [
      {
        source: '/blog/:slug',
        destination: '/news/:slug', // Сопоставленные параметры могут использоваться в destination
      },
    ]
  },
}

Сопоставление путей с подстановочными знаками

Для сопоставления пути с подстановочным знаком можно использовать * после параметра, например /blog/:slug* совпадет с /blog/a/b/c/d/hello-world:

next.config.js
module.exports = {
  async rewrites() {
    return [
      {
        source: '/blog/:slug*',
        destination: '/news/:slug*', // Сопоставленные параметры могут использоваться в destination
      },
    ]
  },
}

Сопоставление путей с регулярными выражениями

Для сопоставления пути с регулярным выражением можно обернуть регулярное выражение в скобки после параметра, например /blog/:slug(\\d{1,}) совпадет с /blog/123, но не с /blog/abc:

next.config.js
module.exports = {
  async rewrites() {
    return [
      {
        source: '/old-blog/:post(\\d{1,})',
        destination: '/blog/:post', // Сопоставленные параметры могут использоваться в destination
      },
    ]
  },
}

Следующие символы (, ), {, }, :, *, +, ? используются для сопоставления путей с регулярными выражениями, поэтому при использовании в source как обычные значения они должны быть экранированы с помощью \\ перед ними:

next.config.js
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.
next.config.js
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 вашего основного приложения на внешний сайт.

next.config.js
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.

next.config.js
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.

next.config.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 к перезаписи:

next.config.js
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 для правильного сопоставления.

next.config.js
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Добавлены заголовки.