Заголовки (headers)
Заголовки позволяют устанавливать пользовательские HTTP-заголовки в ответ на входящий запрос по заданному пути.
Для установки пользовательских HTTP-заголовков можно использовать ключ headers
в 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
.
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
(без вложенных путей):
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
:
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
:
module.exports = {
async headers() {
return [
{
source: '/blog/:post(\\d{1,})',
headers: [
{
key: 'x-post',
value: ':post',
},
],
},
]
},
}
Следующие символы (
, )
, {
, }
, :
, *
, +
, ?
используются для сопоставления путей с регулярными выражениями, поэтому при использовании в source
как обычные значения они должны быть экранированы с помощью \\
перед ними:
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
.
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
к заголовку:
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
для правильного сопоставления.
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 | Добавлены заголовки. |