コンテンツにスキップ

multipart/form-dataのオーバーヘッドを正確に計算する

カテゴリ:HTTP・通信

ファイルアップロードのサイズ上限テストで、「ファイルは9MBなのに413エラーが出る」という経験はありませんか? その原因のひとつが multipart/form-data のオーバーヘッドです。HTMLフォームでファイルをアップロードする際、HTTPリクエストのボディにはファイル本体だけでなく追加のメタデータが含まれます。この記事では、そのオーバーヘッドの正確な計算方法と、テスト時の注意点を解説します。

multipart/form-data の構造

RFC 2046 で定義された multipart/form-data は、各パートを boundary 文字列で区切った構造を持ちます。実際のHTTPリクエストボディはこのようになります。

POST /upload HTTP/1.1
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryABC123
Content-Length: 10000xyz

------WebKitFormBoundaryABC123
Content-Disposition: form-data; name="file"; filename="test.png"
Content-Type: image/png

[ファイルのバイナリデータ]
------WebKitFormBoundaryABC123--

オーバーヘッドの内訳

典型的なファイルアップロードリクエストのオーバーヘッドは以下の要素で構成されます。

要素バイト数(目安)
開始 boundary------WebKitFormBoundaryABC123\r\n約 40〜80 B
Content-Disposition ヘッダーContent-Disposition: form-data; name="file"; filename="test.png"\r\n約 60〜120 B
Content-Type ヘッダーContent-Type: image/png\r\n約 25〜50 B
空行(ヘッダー末尾)\r\n2 B
パート末尾の改行\r\n2 B
終了 boundary------WebKitFormBoundaryABC123--\r\n約 42〜82 B
合計オーバーヘッド約 200〜350 B

ファイル1つだけのシンプルなフォームなら、オーバーヘッドは 200〜400バイト程度 です。追加のフォームフィールド(テキスト入力など)がある場合はその分増えますが、一般的には数百バイト〜数KB程度に収まります。

なぜ413エラーが発生するのか

Nginx の client_max_body_sizeリクエストボディ全体 のサイズを制限します。つまり、設定値にはオーバーヘッドを含む必要があります。

# 10MiB のファイルをアップロードさせたい場合
# オーバーヘッド(約1KB)を考慮して少し大きめに設定
client_max_body_size 11m;  # MiB単位: 11 MiB = 11,534,336 バイト

PHP の場合、upload_max_filesize(ファイル単体)と post_max_size(POSTボディ全体)の2つを設定する必要があります。

; php.ini
upload_max_filesize = 10M   ; ファイル単体の上限: 10 MiB
post_max_size = 11M         ; POSTボディ全体の上限: 11 MiB(オーバーヘッド分を加算)

正確なオーバーヘッドの測定方法

実際のオーバーヘッドを正確に知りたい場合は、curl でリクエストを送信してリクエストサイズを計測できます。

# ファイルのバイト数を確認
wc -c test-10mb.png
# → 10485760 test-10mb.png

# curl でアップロードしてリクエストサイズを確認
curl -X POST https://example.com/upload \
  -F "file=@test-10mb.png" \
  -w "リクエストボディサイズ: %{size_upload} バイト\n" \
  -o /dev/null -s
# → リクエストボディサイズ: 10486062 バイト(差: 302バイト)

Base64エンコードとの違い

multipart/form-data の場合、ファイルのバイナリデータはそのまま送信されます(Base64エンコードなし)。Base64エンコードが必要になるのは、application/x-www-form-urlencoded でバイナリを送る場合や、JSONボディでファイルを送る場合(data:image/png;base64,...`)です。

送信方式オーバーヘッド用途
multipart/form-data(HTMLフォーム)数百B〜数KB通常のファイルアップロード
JSON + Base64約33%増加API経由でのファイル送信
application/octet-stream(PUT)ほぼゼロS3 presigned URL など

テスト時のポイント

  • サーバーの上限チェックが「ファイル単体」か「リクエストボディ全体」かを把握する
  • NginxはPHPの前段でリクエストを制限するため、Nginxの client_max_body_size も確認する
  • 複数ファイルの同時アップロードはオーバーヘッドが増える
  • 追加フォームフィールド(名前、コメントなど)の分もオーバーヘッドに含まれる

DevLab のしきい値テスト用ファイルを使えば、境界付近のファイルサイズで実際のアップロード動作を確認できます。Nginx/Apache/PHPの設定と合わせて検証してください。

まとめ

  • multipart/form-data のオーバーヘッドは 200〜400バイト程度(ファイル1つの場合)
  • Nginx の client_max_body_size はリクエストボディ全体を制限するため、ファイル上限より少し大きく設定する
  • PHPは upload_max_filesize(ファイル単体)と post_max_size(POSTボディ全体)の2つを設定する
  • JSON + Base64 で送信する場合はファイルサイズが約33%増加する

📚 関連記事

PNG vs WebP vs AVIF|画像フォーマットの選び方と変換方法

PNG / JPEG / WebP / AVIF の特徴・用途・ブラウザ対応状況を比較。picture 要素での出し分け、DevLab の画像フォーマット変換ツールの使い方も解説。

2026-04-18

Whois でドメイン情報を調べる方法|有効期限・ネームサーバー・登録者

Whois でわかること (登録者・有効期限・レジストラ・NS)、GDPR によるプライバシー保護の影響、ドメイン管理の実務的な使い方を解説。

2026-04-18

HTTP ステータスコード完全ガイド|よくあるエラーの原因と対処法

開発者が頻出する HTTP ステータスコード (200/301/302/400/401/403/404/413/422/429/500/502/503/504) の意味・原因・対処法を解説。301 vs 302 の SEO 影響、400 vs 422 の使い分けも。

2026-04-18

cURL コマンドを JavaScript fetch・Python requests に変換する方法|DevTools 連携

Chrome DevTools の Copy as cURL を fetch / axios / Python requests / PHP cURL / Go net/http に変換する手順を解説。主要 cURL オプション (-X / -H / -d / -F / -u / -b / -L) の変換パターン、認証トークンの扱い、注意点まで。

2026-04-16

Cookie のセキュリティフラグ完全ガイド|Secure / HttpOnly / SameSite / __Host-

Cookie のセキュリティ属性 Secure / HttpOnly / SameSite (Strict/Lax/None) / __Host- __Secure- プレフィックス / 4096 バイト制限を解説。CSRF / XSS / セッションハイジャック対策と、Laravel / Express の実装例。

2026-04-16

JWT のセキュリティベストプラクティス|alg none 攻撃 / 有効期限 / 署名検証

JWT (JSON Web Token) の代表的な脆弱性 6 種類 (alg none 攻撃 / 鍵混同 / 無期限トークン / payload への機密情報 / 失効不可 / 弱いシークレット) と対策。リフレッシュトークンパターン、失効リスト、HttpOnly Cookie 格納まで。

2026-04-16