Заголовки
Заголовки позволяют устанавливать пользовательские 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',
},
],
},
]
},
}
Сопоставление путей с регулярными выражениями
Для сопоставления пути с регулярным выражением можно заключить регулярное выражение в скобки после параметра, например /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, будет соответствовать любое значение. Можно использовать строку, подобную регулярному выражению, для захвата определённой части значения, например, если значение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',
},
],
},
// если совпадают источник, запрос и куки,
// будет применён заголовок `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
к заголовку:
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 для обеспечения эффективного кэширования ответов и статических ресурсов.
Узнайте больше о кэшировании с маршрутизатором приложений (App Router).
Опции
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.
Этот заголовок заменён опцией CSP frame-ancestors
, которая имеет лучшую поддержку в современных браузерах.
{
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
Этот заголовок контролирует, сколько информации браузер включает при переходе с текущего сайта (origin) на другой.
{
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 | Добавлены заголовки. |