Calcular com precisão o overhead de multipart/form-data
Você já teve a experiência de 「o arquivo tem 9MB, mas aparece erro 413」 em testes de limite de tamanho de upload? Uma das causas é o overhead de <code>multipart/form-data</code>. Ao fazer upload de arquivo via formulário HTML, o corpo da requisição HTTP contém não apenas o arquivo em si, mas também metadados adicionais. Este artigo explica o método preciso de cálculo desse overhead e pontos de atenção durante os testes.
Estrutura de multipart/form-data
O <code>multipart/form-data</code> definido em RFC 2046 possui uma estrutura em que cada parte é separada por uma string boundary. O corpo da solicitação HTTP real fica assim.
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--
Detalhamento do overhead
A sobrecarga de uma solicitação típica de upload de arquivo é composta pelos seguintes elementos.
| Elemento | Exemplo | Número de bytes (estimativa) |
|---|---|---|
| boundary inicial | ------WebKitFormBoundaryABC123\r\n | Aproximadamente 40–80 B |
| Cabeçalho Content-Disposition | Content-Disposition: form-data; name="file"; filename="test.png"\r\n | Aproximadamente 60–120 B |
| Cabeçalho Content-Type | Content-Type: image/png\r\n | Aproximadamente 25–50 B |
| Linha em branco (fim do header) | \r\n | 2 B |
| Quebra de linha no final da parte | \r\n | 2 B |
| boundary de término | ------WebKitFormBoundaryABC123--\r\n | Aproximadamente 42–82 B |
| <strong>Overhead total</strong> | <strong>Cerca de 200–350 B</strong> |
Para um formulário simples com apenas um arquivo, o overhead é aproximadamente <strong>200〜400 bytes</strong>. Se houver campos de formulário adicionais (como entradas de texto), aumentará proporcionalmente, mas geralmente fica dentro de centenas de bytes até alguns KB.
Por que ocorre o erro 413
O <code>client_max_body_size</code> do Nginx limita o tamanho do <strong>corpo da solicitação inteira</strong>. Isso significa que o valor configurado deve incluir overhead.
# 10MiB のファイルをアップロードさせたい場合
# オーバーヘッド(約1KB)を考慮して少し大きめに設定
client_max_body_size 11m; # MiB単位: 11 MiB = 11,534,336 バイト
Em PHP, você precisa configurar dois valores: <code>upload_max_filesize</code> (arquivo individual) e <code>post_max_size</code> (corpo POST inteiro).
; php.ini
upload_max_filesize = 10M ; ファイル単体の上限: 10 MiB
post_max_size = 11M ; POSTボディ全体の上限: 11 MiB(オーバーヘッド分を加算)
Método para medir overhead preciso
Se você quiser conhecer o overhead real com precisão, pode enviar requisições com curl e medir o tamanho da requisição.
# ファイルのバイト数を確認
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バイト)
Diferenças com a codificação Base64
No caso de <code>multipart/form-data</code>, os dados binários do arquivo são enviados como estão (sem codificação Base64). A codificação Base64 é necessária ao enviar dados binários com <code>application/x-www-form-urlencoded</code> ou ao enviar arquivos no corpo JSON (<code>data:image/png;base64,...</code>).
| Método de transmissão | Overhead | Uso |
|---|---|---|
| multipart/form-data (Formulário HTML) | Centenas de B a alguns KB | Upload de arquivo comum |
| JSON + Base64 | Aumento de aproximadamente 33% | Envio de arquivo via API |
| application/octet-stream(PUT) | Quase zero | URLs pré-assinadas do S3 e similares |
Pontos importantes para teste
- Determine se a verificação de limite do servidor é 「arquivo individual」 ou 「corpo da solicitação inteira」
- Como o Nginx limita solicitações em frente do PHP, também verifique <code>client_max_body_size</code> do Nginx
- Upload simultâneo de múltiplos arquivos aumenta o overhead
- O overhead inclui também campos de formulário adicionais (nome, comentários, etc.)
Usando os <a href="/ja/files/threshold/">arquivos para teste de limite</a> do DevLab, você pode verificar o comportamento de upload real com tamanhos de arquivo próximos aos limites. Valide junto com as configurações de Nginx/Apache/PHP.
Resumo
- O overhead de <code>multipart/form-data</code> é <strong>aproximadamente 200-400 bytes</strong> (para um arquivo)
- Como o <code>client_max_body_size</code> do Nginx limita o corpo inteiro da solicitação, configure um valor um pouco maior que o limite de arquivo
- PHP requer a configuração de dois parâmetros: <code>upload_max_filesize</code> (arquivo individual) e <code>post_max_size</code> (corpo POST inteiro)
- Ao enviar com JSON + Base64, o tamanho do arquivo aumenta cerca de 33%
Arquivo de teste disponível para usar neste artigo
- → <a href="/ja/files/threshold/" class="text-primary-600 dark:text-primary-400 hover:underline">Lista de arquivos de teste de limite (9.9MB / 10MB / 10.1MB)</a>
- → <a href="/ja/files/images/png/" class="text-primary-600 dark:text-primary-400 hover:underline">Lista de arquivos de teste de imagem PNG</a>
Artigos relacionados
- → <a href="/ja/blog/how-to-test-upload-limit/" class="text-primary-600 dark:text-primary-400 hover:underline">Como testar corretamente o limite de upload de arquivo</a>
- → <a href="/ja/blog/mb-vs-mib-file-size/" class="text-primary-600 dark:text-primary-400 hover:underline">MB e MiB são diferentes! As armadilhas das unidades de tamanho de arquivo</a>