ヘッダー
ヘッダーを使用すると、特定のパスへのリクエストに対するレスポンスにカスタム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の場合、マッチング時にbasePathが含まれません(外部リライトのみに使用可能)locale
:false
またはundefined
- マッチング時にロケールを含めるかどうかhas
: hasオブジェクトの配列(type
、key
、value
プロパティを持つ)missing
: missingオブジェクトの配列(type
、key
、value
プロパティを持つ)
ヘッダーは、ページや/public
ファイルを含むファイルシステムよりも前にチェックされます。
ヘッダーの上書き動作
同じパスにマッチする2つのヘッダーが同じヘッダーキーを設定している場合、最後のヘッダーキーが最初のものを上書きします。以下のヘッダーを使用すると、パス/hello
では最後に設定された値world
により、ヘッダーx-hello
が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、クエリのマッチング
ヘッダー、Cookie、またはクエリの値もhas
フィールドにマッチする場合、またはmissing
フィールドにマッチしない場合にのみヘッダーを適用するには、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',
},
],
},
// ソース、クエリ、Cookieがマッチする場合、
// `x-authorized`ヘッダーが適用されます
{
source: '/specific/:path*',
has: [
{
type: 'query',
key: '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)/(.*)に変換されるため、
// `/:path*`のようにトップレベルの`/`や`/fr`ルートにはマッチしません
source: '/(.*)',
headers: [
{
key: 'x-hello',
value: 'world',
},
],
},
]
},
}
Cache-Control
next.config.js
でページやアセットのCache-Control
ヘッダーを設定することはできません。これらのヘッダーは本番環境で上書きされ、レスポンスと静的アセットが効果的にキャッシュされるようにします。
静的生成されたページのキャッシュを再検証する必要がある場合、ページのgetStaticProps
関数でrevalidate
プロップを設定することで可能です。
API RoutesでCache-Control
ヘッダーを設定するには、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エンドポイントにアクセスできるようにします。
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年間(max-age
)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を追加する方法について詳しく学びます。
バージョン履歴
バージョン | 変更点 |
---|---|
v13.3.0 | missing 追加。 |
v10.2.0 | has 追加。 |
v9.5.0 | ヘッダー機能追加。 |