Заголовки (headers)

Заголовки позволяют устанавливать пользовательские 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',
          },
        ],
      },
    ]
  },
}

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

Для сопоставления пути с регулярным выражением можно заключить regex в скобки после параметра, например /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, будет соответствовать любое значение. Можно использовать строку, похожую на regex, для захвата определённой части значения, например, если значение 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 не будет доступно в
            // ключах/значениях заголовка, так как value предоставлено и
            // не использует именованную группу захвата, например (?<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

Вы не можете устанавливать заголовки Cache-Control в next.config.js для страниц или ресурсов, так как эти заголовки будут перезаписаны в production для обеспечения эффективного кэширования ответов и статических ресурсов.

Если вам нужно перевалидировать кэш страницы, которая была статически сгенерирована, вы можете сделать это, установив свойство revalidate в функции getStaticProps страницы.

Вы можете установить заголовок Cache-Control в своих API Routes, используя метод res.setHeader:

import type { NextApiRequest, NextApiResponse } from 'next'

type ResponseData = {
  message: string
}

export default function handler(
  req: NextApiRequest,
  res: NextApiResponse<ResponseData>
) {
  res.setHeader('Cache-Control', 's-maxage=86400')
  res.status(200).json({ message: 'Hello from Next.js!' })
}
export default function handler(req, res) {
  res.setHeader('Cache-Control', 's-maxage=86400')
  res.status(200).json({ message: 'Hello from Next.js!' })
}

Опции

CORS

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

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.

Если вы развертываете на Vercel, этот заголовок не требуется, так как он автоматически добавляется ко всем развертываниям, если вы не объявите headers в вашем next.config.js.

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