コンテンツにスキップ

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%増加する

📚 リファレンス