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) и перед динамическими маршрутами. Начиная с версии v10.1 Next.js, когда функция rewrites возвращает объект с массивами определенной структуры, это поведение можно изменить и более тонко контролировать:

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 не проверяют файловую систему/динамические маршруты сразу после сопоставления source, они продолжают проверку, пока не будут проверены все 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, не будут выполнены.

Параметры переадресации

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

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

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

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

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

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

Полезно знать: Параметры из переадресации для статических страниц, созданных с помощью Automatic Static Optimization или prerendering, будут разобраны на клиенте после гидрации и предоставлены в query.

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

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

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

Сопоставление с использованием wildcard

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

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

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

Для сопоставления с регулярным выражением можно заключить regex в скобки после параметра, например /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',
      },
    ]
  },
}

Сопоставление по заголовкам, cookies и query

Чтобы переадресация применялась только при совпадении значений заголовков, cookies или query, можно использовать поле has или missing. Для применения переадресации должны совпадать и source, и все элементы has, а также не должны совпадать все элементы missing.

Элементы has и missing могут иметь следующие поля:

  • type: String — должно быть header, cookie, host или query.
  • key: String — ключ из выбранного типа для сопоставления.
  • value: String или undefined — значение для проверки; если undefined, подойдет любое значение. Можно использовать строку, похожую на regex, для захвата части значения, например, если значение 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',
      },
      // если host — `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Добавлены заголовки.