headers

HTTPヘッダーを使用すると、特定のパスへのリクエストに対するレスポンスにカスタムHTTPヘッダーを設定できます。

カスタムHTTPヘッダーを設定するには、next.config.jsheadersキーを使用します:

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は非同期関数で、sourceheadersプロパティを持つオブジェクトの配列を返す必要があります:

  • source: リクエストパスのパターン
  • headers: レスポンスヘッダーオブジェクトの配列(keyvalueプロパティを持つ)
  • basePath: falseまたはundefined - falseの場合、basePathはマッチング時に含まれません(外部リライトのみに使用可能)
  • locale: falseまたはundefined - ロケールをマッチング時に含めないかどうか
  • has: hasオブジェクトの配列(typekeyvalueプロパティを持つ)
  • missing: missingオブジェクトの配列(typekeyvalueプロパティを持つ)

ヘッダーは、ページや/publicファイルを含むファイルシステムよりも前にチェックされます。

ヘッダーの上書き動作

同じパスにマッチする2つのヘッダーが同じヘッダーキーを設定している場合、最後のヘッダーキーが最初のものを上書きします。以下のヘッダーを使用すると、パス/helloでは最後に設定された値worldが適用され、ヘッダーx-helloworldになります。

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',
          },
        ],
      },
    ]
  },
}

正規表現パスマッチング

正規表現パスにマッチさせるには、パラメータの後に正規表現を括弧で囲みます。例えば/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',
          },
        ],
      },
    ]
  },
}

ヘッダー、Cookie、クエリのマッチング

ヘッダー、Cookie、またはクエリの値がhasフィールドにマッチする場合、またはmissingフィールドにマッチしない場合にのみヘッダーを適用するには、hasフィールドまたはmissingフィールドを使用します。ヘッダーが適用されるためには、sourceとすべてのhasアイテムがマッチし、すべてのmissingアイテムがマッチしない必要があります。

hasmissingアイテムは以下のフィールドを持つことができます:

  • type: String - headercookiehost、またはqueryのいずれか
  • key: String - マッチ対象のキー
  • value: Stringまたはundefined - チェックする値(undefinedの場合は任意の値がマッチ)。値の特定の部分をキャプチャするために正規表現のような文字列を使用できます。例えば、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',
          },
        ],
      },
      // ソース、クエリ、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をヘッダーに追加しない限り):

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)/(.*)に変換されるため、
        // `/:path*`のようにトップレベルの`/`や`/fr`ルートにはマッチしません
        source: '/(.*)',
        headers: [
          {
            key: 'x-hello',
            value: 'world',
          },
        ],
      },
    ]
  },
}

Cache-Control

Next.jsは真に不変なアセットに対してpublic, max-age=31536000, immutableというCache-Controlヘッダーを設定します。これは上書きできません。これらの不変なファイルにはファイル名にSHAハッシュが含まれているため、安全に無期限にキャッシュできます。例えば、静的画像インポートなどです。これらのアセットに対してnext.config.jsCache-Controlヘッダーを設定することはできません。

ただし、他のレスポンスやデータに対してCache-Controlヘッダーを設定することは可能です。

静的生成されたページのキャッシュを再検証する必要がある場合は、ページのgetStaticProps関数でrevalidateプロップを設定することで可能です。

APIルートからのレスポンスをキャッシュするには、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!' })
}

また、getServerSideProps内でキャッシュヘッダー(Cache-Control)を使用して動的レスポンスをキャッシュすることもできます。例えば、stale-while-revalidateを使用します。

import { GetStaticProps, GetStaticPaths, GetServerSideProps } from 'next'

// この値は10秒間新鮮とみなされます(s-maxage=10)。
// 次の10秒以内にリクエストが繰り返されると、以前に
// キャッシュされた値がまだ新鮮な状態で使用されます。59秒以内にリクエストが繰り返されると、
// キャッシュされた値は古くなりますが、まだレンダリングされます(stale-while-revalidate=59)。
//
// バックグラウンドで、キャッシュを新しい値で更新するための再検証リクエストが行われます。
// ページを更新すると、新しい値が表示されます。
export const getServerSideProps = (async (context) => {
  context.res.setHeader(
    'Cache-Control',
    'public, s-maxage=10, stale-while-revalidate=59'
  )

  return {
    props: {},
  }
}) satisfies GetServerSideProps

オプション

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でのみ提供できるページやサブドメインへのアクセスをブロックします。

{
  key: 'Strict-Transport-Security',
  value: 'max-age=63072000; includeSubDomains; preload'
}

X-Frame-Options

このヘッダーは、サイトがiframe内に表示されることを許可するかどうかを示します。これはクリックジャッキング攻撃を防ぐことができます。

このヘッダーは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

このヘッダーは、現在のウェブサイト(オリジン)から別のサイトに移動する際に、ブラウザがどの程度の情報を含めるかを制御します。

{
  key: 'Referrer-Policy',
  value: 'origin-when-cross-origin'
}

Content-Security-Policy

アプリケーションにコンテンツセキュリティポリシーを追加する方法について詳しく学びましょう。

バージョン履歴

バージョン変更内容
v13.3.0missing 追加
v10.2.0has 追加
v9.5.0ヘッダー追加