Переадресация (rewrites)

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

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

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: [
        // Эти переадресации проверяются после проверки страниц/public файлов,
        // но перед динамическими маршрутами
        {
          source: '/non-existent',
          destination: '/somewhere-else',
        },
      ],
      fallback: [
        // Эти переадресации проверяются после проверки как страниц/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, не будут выполнены.

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

При использовании параметров в переадресации параметры по умолчанию передаются в запросе, если ни один из параметров не используется в 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, запрос и кука,
      // будет применена эта переадресация
      {
        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Добавлены заголовки.