headers
ヘッダを使用すると、指定されたパスへのリクエスト応答にカスタムHTTPヘッダを設定できます。
カスタムHTTPヘッダを設定するには、next.config.js
でheaders
キーを使用します:
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
の場合、ベースパスはマッチングに含まれず、外部のリライトにのみ使用されますlocale
:false
またはundefined
- ロケールがマッチングに含まれないようにしますhas
は、type
,key
,value
プロパティを持つhasオブジェクトの配列ですmissing
は、type
,key
,value
プロパティを持つmissingオブジェクトの配列です
ヘッダは、ページおよび/public
フォルダ内のファイルを含むファイルシステムより前にチェックされます。
ヘッダーの上書き動作
2つのヘッダが同じパスにマッチし、同じヘッダーキーを設定する場合、最後のヘッダーキーが最初のものを上書きします。以下のヘッダを使用すると、パス/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',
},
],
},
]
},
}
ヘッダー、Cookieおよびクエリのマッチング
ヘッダーがhas
フィールドと一致するか、missing
フィールドと一致しない場合にのみヘッダーを適用するには、それを使用します。source
とすべてのhas
項目がマッチし、すべてのmissing
項目が一致しない場合にヘッダーが適用されます。
has
とmissing
項目には次のフィールドがあります:
type
:String
-header
、cookie
、host
、query
のいずれかである必要がありますkey
:String
- 選択したタイプからマッチするキーvalue
:String
またはundefined
- チェックする値、undefinedの場合は任意の値と一致します。正規表現のような文字列を使用して値の特定の部分をキャプチャすることができます。例えば、値がfirst-(?<paramName>.*)
の場合、first-second
の次に:paramName
を使用して宛先でsecond
を利用できます。
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値はヘッダーキー/値で使用できません
// 正規表現の名前付きキャプチャグループを使用しないため e.g. (?<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
Next.jsは、Cache-Control
ヘッダーにpublic, max-age=31536000, immutable
を設定しています。本当に不変なアセットには上書きできません。これらの不変なファイルはファイル名にSHAハッシュを含んでいるため、安全に無期限でキャッシュできます。例えば、Static Image Imports。これらの資産に対するCache-Control
ヘッダーをnext.config.js
で設定することはできません。
ただし、他の応答やデータに対してCache-Control
ヘッダーを設定することはできます。
App Routerでのキャッシュに関して詳しく学びましょう。
オプション
CORS
クロスオリジンリソース共有(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
このヘッダーはブラウザに対して、HTTPではなくHTTPSを使用してのみアクセスされなければならないことを通知します。以下の設定を使用すると、すべての現在および将来のサブドメインが2年間HTTPSを使用します。これにより、HTTPでしか提供できないページやサブドメインへのアクセスがブロックされます。
Vercelにデプロイしている場合、このヘッダーはすべてのデプロイに自動的に追加されるため、next.config.js
でheaders
を宣言しない限り必要ありません。
{
key: 'Strict-Transport-Security',
value: 'max-age=63072000; includeSubDomains; preload'
}
X-Frame-Options
このヘッダーは、サイトがiframe
内で表示されるべきかどうかを示します。これはクリックジャッキング攻撃を防ぐことができます。
このヘッダーはCSPのframe-ancestors
オプションによって置き換えられました。このオプションは、現代のブラウザでよりよくサポートされています(設定の詳細については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を追加する方法について詳しく学びます。
バージョン履歴
Version | Changes |
---|---|
v13.3.0 | missing が追加されました |
v10.2.0 | has が追加されました |
v9.5.0 | ヘッダーが追加されました |