Заголовки

Заголовки позволяют устанавливать пользовательские HTTP-заголовки в ответ на входящий запрос по заданному пути.

Для установки пользовательских HTTP-заголовков можно использовать ключ headers в next.config.js:

next.config.js
module.exports = {
  async headers() {
    return [
      {
        source: '/about',
        headers: [
          {
            key: 'x-custom-header',
            value: 'my custom header value',
          },
          {
            key: 'x-another-custom-header',
            value: 'my other custom header value',
          },
        ],
      },
    ]
  },
}

headers — это асинхронная функция, которая ожидает возврата массива объектов со свойствами source и headers:

  • source — шаблон пути входящего запроса.
  • headers — массив объектов заголовков ответа с свойствами key и value.
  • basePath: false или undefined — если false, basePath не будет учитываться при сопоставлении, может использоваться только для внешних перезаписей.
  • locale: false или undefined — указывает, следует ли исключать локаль при сопоставлении.
  • has — массив объектов has со свойствами type, key и value.
  • missing — массив объектов missing со свойствами type, key и value.

Заголовки проверяются до файловой системы, которая включает страницы и файлы /public.

Поведение переопределения заголовков

Если два заголовка соответствуют одному и тому же пути и устанавливают один и тот же ключ заголовка, последний ключ заголовка переопределит первый. Используя приведенные ниже заголовки, путь /hello приведет к тому, что заголовок x-hello будет иметь значение world, поскольку последнее установленное значение заголовка — world.

next.config.js
module.exports = {
  async headers() {
    return [
      {
        source: '/:path*',
        headers: [
          {
            key: 'x-hello',
            value: 'there',
          },
        ],
      },
      {
        source: '/hello',
        headers: [
          {
            key: 'x-hello',
            value: 'world',
          },
        ],
      },
    ]
  },
}

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

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

next.config.js
module.exports = {
  async headers() {
    return [
      {
        source: '/blog/:slug',
        headers: [
          {
            key: 'x-slug',
            value: ':slug', // Сопоставленные параметры могут использоваться в значении
          },
          {
            key: 'x-slug-:slug', // Сопоставленные параметры могут использоваться в ключе
            value: 'my other custom header value',
          },
        ],
      },
    ]
  },
}

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

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

next.config.js
module.exports = {
  async headers() {
    return [
      {
        source: '/blog/:slug*',
        headers: [
          {
            key: 'x-slug',
            value: ':slug*', // Сопоставленные параметры могут использоваться в значении
          },
          {
            key: 'x-slug-:slug*', // Сопоставленные параметры могут использоваться в ключе
            value: 'my other custom header value',
          },
        ],
      },
    ]
  },
}

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

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

next.config.js
module.exports = {
  async headers() {
    return [
      {
        source: '/blog/:post(\\d{1,})',
        headers: [
          {
            key: 'x-post',
            value: ':post',
          },
        ],
      },
    ]
  },
}

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

next.config.js
module.exports = {
  async headers() {
    return [
      {
        // это будет соответствовать запросу `/english(default)/something`
        source: '/english\\(default\\)/:slug',
        headers: [
          {
            key: 'x-header',
            value: 'value',
          },
        ],
      },
    ]
  },
}

Сопоставление заголовков, куки и запросов

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

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

  • type: String — должно быть header, cookie, host или query.
  • key: String — ключ из выбранного типа для сопоставления.
  • value: String или undefined — значение для проверки, если undefined, будет соответствовать любое значение. Можно использовать строку, подобную регулярному выражению, для захвата определенной части значения, например, если значение first-(?<paramName>.*) используется для first-second, то second можно будет использовать в назначении с :paramName.
next.config.js
module.exports = {
  async headers() {
    return [
      // если присутствует заголовок `x-add-header`,
      // будет применен заголовок `x-another-header`
      {
        source: '/:path*',
        has: [
          {
            type: 'header',
            key: 'x-add-header',
          },
        ],
        headers: [
          {
            key: 'x-another-header',
            value: 'hello',
          },
        ],
      },
      // если заголовок `x-no-header` отсутствует,
      // будет применен заголовок `x-another-header`
      {
        source: '/:path*',
        missing: [
          {
            type: 'header',
            key: 'x-no-header',
          },
        ],
        headers: [
          {
            key: 'x-another-header',
            value: 'hello',
          },
        ],
      },
      // если совпадают source, query и cookie,
      // будет применен заголовок `x-authorized`
      {
        source: '/specific/:path*',
        has: [
          {
            type: 'query',
            key: 'page',
            // значение page не будет доступно в ключах/значениях заголовка,
            // так как значение предоставлено и не использует именованную группу захвата, например (?<page>home)
            value: 'home',
          },
          {
            type: 'cookie',
            key: 'authorized',
            value: 'true',
          },
        ],
        headers: [
          {
            key: 'x-authorized',
            value: ':authorized',
          },
        ],
      },
      // если заголовок `x-authorized` присутствует и
      // содержит соответствующее значение, будет применен `x-another-header`
      {
        source: '/:path*',
        has: [
          {
            type: 'header',
            key: 'x-authorized',
            value: '(?<authorized>yes|true)',
          },
        ],
        headers: [
          {
            key: 'x-another-header',
            value: ':authorized',
          },
        ],
      },
      // если хост — `example.com`,
      // этот заголовок будет применен
      {
        source: '/:path*',
        has: [
          {
            type: 'host',
            value: 'example.com',
          },
        ],
        headers: [
          {
            key: 'x-another-header',
            value: ':authorized',
          },
        ],
      },
    ]
  },
}

Заголовки с поддержкой basePath

При использовании поддержки basePath с заголовками каждый source автоматически дополняется basePath, если вы не добавите basePath: false к заголовку:

next.config.js
module.exports = {
  basePath: '/docs',

  async headers() {
    return [
      {
        source: '/with-basePath', // становится /docs/with-basePath
        headers: [
          {
            key: 'x-hello',
            value: 'world',
          },
        ],
      },
      {
        source: '/without-basePath', // не изменяется, так как установлено basePath: false
        headers: [
          {
            key: 'x-hello',
            value: 'world',
          },
        ],
        basePath: false,
      },
    ]
  },
}

Заголовки с поддержкой i18n

При использовании поддержки i18n с заголовками каждый source автоматически дополняется для обработки настроенных locales, если вы не добавите locale: false к заголовку. Если используется locale: false, вы должны добавить локаль к source для правильного сопоставления.

next.config.js
module.exports = {
  i18n: {
    locales: ['en', 'fr', 'de'],
    defaultLocale: 'en',
  },

  async headers() {
    return [
      {
        source: '/with-locale', // автоматически обрабатывает все локали
        headers: [
          {
            key: 'x-hello',
            value: 'world',
          },
        ],
      },
      {
        // не обрабатывает локали автоматически, так как установлено locale: false
        source: '/nl/with-locale-manual',
        locale: false,
        headers: [
          {
            key: 'x-hello',
            value: 'world',
          },
        ],
      },
      {
        // соответствует '/', так как `en` — defaultLocale
        source: '/en',
        locale: false,
        headers: [
          {
            key: 'x-hello',
            value: 'world',
          },
        ],
      },
      {
        // преобразуется в /(en|fr|de)/(.*), поэтому не будет соответствовать корневым
        // маршрутам `/` или `/fr`, как это сделал бы /:path*
        source: '/(.*)',
        headers: [
          {
            key: 'x-hello',
            value: 'world',
          },
        ],
      },
    ]
  },
}

Cache-Control

Next.js устанавливает заголовок Cache-Control со значением public, max-age=31536000, immutable для действительно неизменяемых ресурсов. Это нельзя переопределить. Эти неизменяемые файлы содержат SHA-хэш в имени файла, поэтому их можно безопасно кэшировать на неопределенный срок. Например, Статические импорты изображений. Вы не можете установить заголовки Cache-Control в next.config.js для этих ресурсов.

Однако вы можете установить заголовки Cache-Control для других ответов или данных.

Узнайте больше о кэшировании с помощью маршрутизатора App.

Опции

CORS

Cross-Origin Resource Sharing (CORS) — это функция безопасности, которая позволяет контролировать, какие сайты могут получать доступ к вашим ресурсам. Вы можете установить заголовок Access-Control-Allow-Origin, чтобы разрешить доступ к вашим Route Handlers с определенного источника.

async headers() {
    return [
      {
        source: "/api/:path*",
        headers: [
          {
            key: "Access-Control-Allow-Origin",
            value: "*", // Укажите ваш источник
          },
          {
            key: "Access-Control-Allow-Methods",
            value: "GET, POST, PUT, DELETE, OPTIONS",
          },
          {
            key: "Access-Control-Allow-Headers",
            value: "Content-Type, Authorization",
          },
        ],
      },
    ];
  },

X-DNS-Prefetch-Control

Этот заголовок управляет предварительной выборкой DNS, позволяя браузерам заранее выполнять разрешение доменных имен для внешних ссылок, изображений, CSS, JavaScript и других ресурсов. Эта предварительная выборка выполняется в фоновом режиме, поэтому DNS с большей вероятностью будет разрешен к моменту, когда ссылки понадобятся. Это уменьшает задержку при переходе пользователя по ссылке.

{
  key: 'X-DNS-Prefetch-Control',
  value: 'on'
}

Strict-Transport-Security

Этот заголовок сообщает браузерам, что доступ должен осуществляться только через HTTPS, а не через HTTP. Используя приведенную ниже конфигурацию, все текущие и будущие поддомены будут использовать HTTPS в течение max-age 2 года. Это блокирует доступ к страницам или поддоменам, которые могут быть доступны только через HTTP.

{
  key: 'Strict-Transport-Security',
  value: 'max-age=63072000; includeSubDomains; preload'
}

X-Frame-Options

Этот заголовок указывает, разрешено ли отображение сайта внутри iframe. Это может предотвратить атаки типа clickjacking.

Этот заголовок заменен опцией frame-ancestors в CSP, которая имеет лучшую поддержку в современных браузерах (см. Content Security Policy для деталей конфигурации).

{
  key: 'X-Frame-Options',
  value: 'SAMEORIGIN'
}

Permissions-Policy

Этот заголовок позволяет управлять, какие функции и API могут использоваться в браузере. Ранее он назывался Feature-Policy.

{
  key: 'Permissions-Policy',
  value: 'camera=(), microphone=(), geolocation=(), browsing-topics=()'
}

X-Content-Type-Options

Этот заголовок предотвращает попытки браузера угадать тип контента, если заголовок Content-Type не задан явно. Это может предотвратить XSS-атаки на сайтах, которые позволяют пользователям загружать и обмениваться файлами.

Например, когда пользователь пытается скачать изображение, но оно обрабатывается как другой Content-Type, например исполняемый файл, который может быть вредоносным. Этот заголовок также применяется к загрузке расширений браузера. Единственное допустимое значение для этого заголовка — nosniff.

{
  key: 'X-Content-Type-Options',
  value: 'nosniff'
}

Referrer-Policy

Этот заголовок контролирует, сколько информации браузер включает при переходе с текущего сайта (источника) на другой.

{
  key: 'Referrer-Policy',
  value: 'origin-when-cross-origin'
}

Content-Security-Policy

Узнайте больше о добавлении Политики безопасности контента (Content Security Policy) в ваше приложение.

История версий

ВерсияИзменения
v13.3.0Добавлено missing.
v10.2.0Добавлено has.
v9.5.0Добавлены заголовки.