Menu

headers

ヘッダーを使用すると、指定されたパスへの受信リクエストに対するレスポンスにカスタム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は、sourceおよびheadersプロパティを持つオブジェクトを含む配列を返すことが期待される非同期関数です。

  • sourceは受信リクエストパスパターンです。
  • headerskeyおよびvalueプロパティを持つレスポンスヘッダーオブジェクトの配列です。
  • basePathfalseまたはundefined - falseの場合、マッチング時にbasePathが含まれません。外部リライトでのみ使用できます。
  • localefalseまたはundefined - マッチング時にロケールを含めるかどうか。
  • hastypekey、およびvalueプロパティを持つhasオブジェクトの配列です。
  • missingtypekey、およびvalueプロパティを持つmissingオブジェクトの配列です。

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

ヘッダー上書き動作

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

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', // マッチしたパラメータはvalueで使用できます
          },
          {
            key: 'x-slug-:slug', // マッチしたパラメータはkeyで使用できます
            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*', // マッチしたパラメータはvalueで使用できます
          },
          {
            key: 'x-slug-:slug*', // マッチしたパラメータはkeyで使用できます
            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項目はマッチしない必要があります。

hasおよびmissing項目には次のフィールドを含めることができます。

  • typeString - headercookiehost、またはqueryのいずれかである必要があります。
  • keyString - マッチさせる選択されたタイプのキー。
  • valueStringまたはundefined - チェックする値。未定義の場合、任意の値がマッチします。値の特定部分をキャプチャするために正規表現のような文字列を使用できます。例えば、値first-(?<paramName>.*)first-secondに対して使用される場合、secondはdestinationで: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の値は名前付きキャプチャグループを使用しないため、
            // ヘッダーのキー/値では利用できません。例えば(?<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)/(.*)に変換されるため、トップレベルの
        // `/`または`/fr`ルートのような/:path*にはマッチしません
        source: '/(.*)',
        headers: [
          {
            key: 'x-hello',
            value: 'world',
          },
        ],
      },
    ]
  },
}

Cache-Control

Next.jsは、本当に変わらないアセットに対してpublic, max-age=31536000, immutableCache-Controlヘッダーを設定します。これはオーバーライドできません。これらの変わらないファイルには、ファイル名にSHA-ハッシュが含まれているため、安全に無期限にキャッシュできます。例えば、静的イメージインポートです。next.config.jsでこれらのアセットに対してCache-Controlヘッダーを設定することはできません。

ただし、他のレスポンスまたはデータに対してCache-Controlヘッダーを設定できます。

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

APIルートからのレスポンスをキャッシュするには、res.setHeaderを使用できます。

pages/api/hello.ts
TypeScript
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を使用します。

pages/index.tsx
TypeScript
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

クロスオリジンリソースシェアリング(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ヘッダーが明示的に設定されていない場合、ブラウザがコンテンツのタイプを推測しようとするのを防止します。これにより、ユーザーがファイルをアップロードして共有できるWebサイトのXSS悪用を防止できます。

例えば、ユーザーがイメージをダウンロードしようとしているが、実行ファイルなどの別のContent-Typeとして処理され、悪意がある可能性があります。このヘッダーはブラウザ拡張機能のダウンロードにも適用されます。このヘッダーの唯一の有効な値はnosniffです。

{
  key: 'X-Content-Type-Options',
  value: 'nosniff'
}

Referrer-Policy

このヘッダーは、現在のWebサイト(オリジン)から別のサイトへナビゲートする際に、ブラウザが含める情報の量を制御します。

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

Content-Security-Policy

アプリケーションにコンテンツセキュリティポリシーを追加する方法の詳細を学習します。

バージョン履歴

バージョン変更内容
v13.3.0missingが追加されました。
v10.2.0hasが追加されました。
v9.5.0ヘッダーが追加されました。