HTTPリクエストヘッダサイズ上限が本番で予期せず超過する仕組み──仕様書と現場の実装ズレ

開発環境では通るのに、本番でヘッダサイズエラーが出る

開発チームから連絡が来ました。「本番環境でだけ、特定のAPIリクエストが400エラーになる。開発環境では正常に動いている」。

調査してみると、原因はHTTPリクエストヘッダのサイズ超過でした。クライアント側でセッション情報、トラッキングIDなど複数のカスタムヘッダを積み重ねていたところ、本番環境のWebサーバー設定では許容サイズが開発環境より厳しく設定されていたのです。

このような問題は「設定の違い」と片付けられることが多いのですが、実際には、仕様書と実装、そして運用環境の設定が個別に決められていく中で、自然と発生する構造的な課題です。今回は、この問題がなぜ起きるのか、どう検証すべきか、実務的な対策までを整理します。

Webサーバーのヘッダサイズ上限は複層構造

HTTPヘッダサイズの制限は、複数のレイヤーで独立に設定されています。これが問題を複雑にする主な原因です。

一般的な制限ポイント:

  • Webサーバー(Nginx、Apache)の設定値
  • リバースプロキシ(ロードバランサー)の設定値
  • アプリケーションフレームワークの設定値
  • クライアント側のHTTPライブラリの制限

Nginxを例に取ると、client_header_buffer_sizelarge_client_header_buffers という2つのディレクティブで制御されます。デフォルトは前者が4KB、後者が4個の8KBバッファです。

# デフォルト設定
client_header_buffer_size 4k;
large_client_header_buffers 4 8k;

# これを超えると 413 Request Entity Too Large または 400 Bad Request

開発環境では、デフォルト値のままか、あるいは「テスト用に大きめに設定」されていることが多いです。一方、本番環境ではセキュリティポリシーに基づいて厳しく設定されることが多く、その差が出現するわけです。

仕様書と実装のズレが起きやすい理由

API仕様書では「カスタムヘッダXを追加する」と書かれていても、そのヘッダが複数の箇所で追加されるうちに、サイズが積み重なっていく現象が起きます。

現場でよく見かけるパターン:

  1. ミドルウェアレベルで認証トークンを追加
  2. ロギング用にX-Request-IDを追加
  3. トレーシング用に複数のスパン情報を追加
  4. クライアント側でセッション情報を追加
  5. キャッシュ制御用のヘッダを追加

個々のヘッダは小さくても、合計すると数KBに達することがあります。特に、トレーシングやトラッキング情報は、階層が深くなるほどヘッダに追加され続ける傾向があります。

さらに、API仕様書には「ヘッダサイズの上限」という項目がそもそも記載されていないことがほとんどです。記載されていても、Webサーバー側の設定値との連携が明示されていません。

検証の進め方──開発環境で上限を再現する

実務的には、以下の検証手順をお勧めします。

ステップ1:現在のヘッダサイズを測定

開発環境で、実際のリクエストに含まれるヘッダ総量を計測します。ブラウザの開発者ツールやHTTPクライアントツール(curlやPostmanなど)でヘッダを確認し、合計バイト数を記録します。

# curlで実際のリクエストヘッダを表示
curl -v https://api.example.com/endpoint \
  -H "X-Custom-Header: value1" \
  -H "X-Trace-ID: trace-id-value" \
  -H "Authorization: Bearer token..." \
  2>&1 | grep "^>"

ステップ2:開発環境のWebサーバー設定を確認

現在の設定値を把握します。

# Nginxの場合
nginx -T | grep -i header_buffer

ステップ3:本番環境の設定値を取得

インフラ担当者に確認するか、ドキュメントから取得します。ここで初めて「開発環境と異なる」ことが判明することが多いです。

ステップ4:開発環境で本番の制限を再現

開発環境のWebサーバー設定を本番値に合わせて、同じリクエストを送信して動作確認します。

# 開発環境を本番設定に合わせる例
client_header_buffer_size 2k;
large_client_header_buffers 2 4k;

この時点で、開発環境でも同じエラーが再現できれば、問題の原因と対策の方向性が明確になります。

実装側の対策──ヘッダ設計の見直し

ヘッダサイズが上限に接近していた場合、以下の対策が考えられます。

1. 不要なヘッダの削除

トレーシング情報やトラッキング情報の中に、実際には使われていないものがないか確認します。特に、複数のトレーシングシステムが並行して動いている場合、重複している可能性があります。

2. ヘッダの圧縮またはBody化

複数の小さなヘッダを1つに統合したり、情報をリクエストボディに移動したりすることで、ヘッダサイズを削減できます。

// ❌ 複数のヘッダで情報を送る
headers: {
  'X-User-ID': userId,
  'X-Session-ID': sessionId,
  'X-Trace-ID': traceId,
  'X-Span-ID': spanId,
  'X-Parent-Span-ID': parentSpanId,
}

// ✅ 1つのヘッダにJSON化して送る
headers: {
  'X-Context': JSON.stringify({
    userId, sessionId, traceId, spanId, parentSpanId
  })
}

3. Webサーバー設定の調整

アプリケーション側で削減できない場合、本番環境のWebサーバー設定を拡大することも検討します。ただし、セキュリティポリシーの確認が必須です。

運用・保守の観点から

この問題は、一度修正しても、時間経過とともに再発しやすい特性があります。

理由:

  • 新しいトレーシング機能やロギング機能が追加されるたびに、ヘッダが増える
  • 開発環境と本番環境の設定差が、ドキュメント化されていないことが多い
  • ヘッダサイズは「パフォーマンステスト」の対象になりにくい

予防策として:

  • API仕様書に「ヘッダサイズの上限と、本番環境での制限値」を明記
  • 定期的に本番環境のWebサーバー設定を開発環境に反映させるプロセスを組み込む
  • 統合テスト時に、本番相当の設定下でのリクエスト送信をテストケースに含める

向いている案件と注意点

この検証アプローチが活躍する場面は、以下のような環境です。

向いている:

  • 複数のマイクロサービスが連携し、各層でヘッダが追加される構成
  • トレーシング・ロギング・認証などが複数並行している
  • 開発環境と本番環境の管理が別チームである

注意点:

  • ヘッダサイズの計測は、負荷テスト時に同時実行数が多い場合のメモリ使用量にも影響する
  • 制限値を拡大する場合は、DDoS対策としての役割も担っていることを認識しておく

実務では「なぜそのサイズ制限なのか」という背景を理解することが、適切な判断につながります。