multipart/form-data의 오버헤드를 정확하게 계산하기
파일 업로드 크기 제한 테스트에서 「파일은 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--
오버헤드 내역
일반적인 파일 업로드 요청의 오버헤드는 다음 요소로 구성됩니다.
| 요소 | 예시 | 바이트 수 (목안) |
|---|---|---|
| 시작 경계 | ------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\n | 2 B |
| 파트 말미의 줄바꿈 | \r\n | 2 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) | 거의 0에 가까움 | S3 서명된 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 본문 전체) 두 가지를 설정해야 합니다. - JSON + Base64로 전송할 경우 파일 크기가 약 33% 증가합니다