Multipart Upload es un mecanismo HTTP que permite transferir varias partes heterogéneas de datos en una sola solicitud, incluidos campos de texto y archivos binarios. Cada parte se separa mediante una cadena de límite única y tiene su propio encabezado Content-Type. Según MDN Web Docs, 2025, multipart/form-data es el formato estándar para cargar archivos a través de formularios HTML y se utiliza ampliamente en aplicaciones web y móviles para enviar imágenes, documentos y otros archivos al servidor.
Puntos clave
Multipart Upload es un método de transferencia de datos mediante el protocolo HTTP en el que el cuerpo de la solicitud consta de varias partes lógicamente separadas. Cada parte puede contener datos de diferente tipo: un campo de texto de formulario, un archivo binario, un objeto JSON o una imagen. Todas las partes se empaquetan en una sola solicitud POST, eliminando la necesidad de enviar N llamadas HTTP separadas. Multipart Upload es una parte esencial de los formularios web y las API de carga de archivos.
El formato multipart fue definido en la especificación RFC 2046 como parte del estándar MIME para mensajes de correo electrónico, y luego se adaptó para HTTP en RFC 1867. Hoy en día, el desarrollo web utiliza casi exclusivamente multipart/form-data, uno de los subtipos multipart diseñados para formularios que contienen archivos. Otros subtipos (multipart/mixed para adjuntos arbitrarios y multipart/byteranges para descargas parciales de archivos) se utilizan con mucha menos frecuencia.
La diferencia fundamental entre multipart y application/x-www-form-urlencoded es que este último codifica todos los datos en una cadena compatible con URI y no admite archivos binarios. Multipart/form-data, por el contrario, transmite cada archivo en su forma binaria original sin codificación, lo que es más eficiente y no pierde precisión. El tamaño de la solicitud con multipart siempre es un 5-15% mayor que la suma de los tamaños de los archivos debido a la sobrecarga de los encabezados de las partes y los límites.
Multipart Upload se utiliza en cualquier lugar donde se requiera la carga de archivos: avatares y fotos de perfil en redes sociales, archivos adjuntos en mensajería, documentos en sistemas CRM, imágenes de productos en tiendas online. En aplicaciones móviles, Multipart Upload se utiliza para enviar archivos multimedia al servidor: fotos de la cámara del dispositivo, grabaciones de voz, clips de video. Según Cloudflare Research, alrededor del 15% de todas las solicitudes POST en la web utilizan multipart/form-data.
Multipart Upload y Chunked Transfer son mecanismos diferentes. Multipart divide una solicitud en partes con significado (campos y archivos), mientras que Chunked Transfer divide un flujo de datos en fragmentos para su transmisión sin conocer el tamaño total. Multipart puede transmitirse dentro de Chunked Transfer: el servidor envía una respuesta multipart por partes sin conocer su tamaño completo. Estos mecanismos no entran en conflicto y resuelven diferentes problemas en diferentes niveles.
Cuando un navegador envía un formulario con el atributo enctype="multipart/form-data", construye el cuerpo de la solicitud en formato multipart. Cada campo del formulario se convierte en un bloque separado, separado de los demás por una cadena de límite (boundary). El límite se genera automáticamente y es una secuencia única de caracteres que garantiza no aparecer dentro de los datos. El cliente añade este límite al encabezado Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryX7K.
Cada bloque comienza con --boundary y contiene encabezados Content-Disposition con el nombre del campo (name) y, para archivos, el nombre original del archivo (filename). Después de una línea en blanco vienen los datos del campo o el contenido del archivo en forma binaria. La solicitud termina con la cadena --boundary--. El servidor analiza el flujo recibido: primero encuentra el límite, luego extrae los encabezados de cada parte, determina el tipo de datos y los pasa al controlador del formulario o a la API.
Según IETF RFC 7578, multipart/form-data no requiere especificar un charset para cada parte, ya que los campos de texto se consideran en UTF-8 y las partes binarias contienen archivos en su codificación original. El tamaño de una parte no está limitado por el protocolo: los límites se configuran a nivel del servidor, por ejemplo, en Nginx mediante client_max_body_size, en Spring Boot mediante spring.servlet.multipart.max-file-size.
Boundary es una cadena única que no debe aparecer en los datos transmitidos. Por lo general, comienza con un prefijo (por ejemplo, ----WebKitFormBoundary o ----Boundary) y contiene caracteres aleatorios. Los navegadores y clientes HTTP generan el boundary automáticamente. La longitud del boundary no debe superar los 70 caracteres según RFC 2046. Cada parte se separa con la cadena --boundary\r\n, y el final de la solicitud se marca con --boundary--\r\n.
Una solicitud multipart tiene una estructura estricta definida por los estándares MIME y HTTP. El encabezado de la solicitud establece Content-Type: multipart/form-data con un parámetro boundary. El cuerpo de la solicitud consta de una secuencia de partes, cada una con sus propios encabezados y cuerpo. Los encabezados de la parte incluyen Content-Disposition (obligatorio) y Content-Type (opcional, para archivos). Es obligatorio tener una línea en blanco entre los encabezados de la parte y sus datos.
| Elemento | Ejemplo | Obligatorio |
|---|---|---|
| Content-Type | multipart/form-data; boundary=---Bnd123 | Sí |
| Delimitador de parte | ---Bnd123 | Sí (antes de cada parte) |
| Content-Disposition | form-data; name="avatar"; filename="photo.jpg" | Sí |
| Content-Type de parte | image/jpeg | Para archivos |
| Cuerpo de la parte | [datos binarios de imagen] | Sí |
| Límite final | ---Bnd123-- | Sí (fin de solicitud) |
Consideremos un ejemplo real de una solicitud multipart que envía un campo de texto y un archivo de imagen. El cliente forma el encabezado Content-Type con un boundary único. El cuerpo de la solicitud contiene secuencialmente todos los campos del formulario. Al recibirlo, el servidor analiza estas partes y proporciona al desarrollador acceso a cada campo como un objeto separado. Este enfoque permite procesar formularios complejos con archivos en una sola llamada HTTP.
import okhttp3.*
import java.io.File
fun uploadFile() {
val client = OkHttpClient()
val imageFile = File("/path/to/photo.jpg")
val requestBody = MultipartBody.Builder()
.setType(MediaType.parse("multipart/form-data"))
.addFormDataPart("username", "john_doe")
.addFormDataPart(
"avatar", "photo.jpg",
RequestBody.create(
MediaType.parse("image/jpeg"), imageFile
)
)
.build()
val request = Request.Builder()
.url("https://api.example.com/upload")
.post(requestBody)
.build()
client.newCall(request).execute().use { response ->
println("Cargado: ${response.isSuccessful}")
}
}
En el lado del servidor, la solicitud multipart se analiza mediante el framework o manualmente. En Spring Boot, basta con la anotación @RequestParam("avatar") MultipartFile file, y el framework extrae automáticamente el archivo de la solicitud multipart. En Ktor en Kotlin se usa receiveMultipart(), en Express.js — el middleware multer. El servidor obtiene acceso a cada campo del formulario y a cada archivo cargado de forma independiente, guarda el archivo en disco o almacenamiento en la nube y devuelve una URL o identificador al cliente.
Multipart Upload ofrece varias ventajas clave sobre los métodos alternativos de transferencia de datos. Una solicitud en lugar de muchas: todos los campos del formulario y archivos se transmiten en una sola llamada HTTP, lo que reduce la carga en la red y el servidor. No es necesario abrir N conexiones para cargar N archivos: todo se empaqueta en un solo POST. Esto es especialmente importante para aplicaciones móviles, donde cada conexión HTTP significa latencia y consumo de batería.
Transferencia binaria sin codificación: a diferencia de application/x-www-form-urlencoded, donde los datos binarios se codifican en base64 (aumentando el tamaño en un 33%), multipart/form-data transmite los archivos en su forma binaria original. Esto es más eficiente en tamaño y velocidad. Para archivos grandes de más de 10 MB, la diferencia se vuelve crítica: una solicitud multipart será un 30% más pequeña que una solicitud codificada en URL con el mismo archivo.
Estructura arbitraria: multipart permite combinar campos de diferentes tipos en cualquier orden. Un formulario puede contener campos de texto, múltiples archivos, datos JSON y campos ocultos simultáneamente. Cada parte tiene su propio Content-Type, lo que permite mezclar datos de texto y binarios. En comparación: la codificación base64 añade un 33% al tamaño, mientras que multipart añade solo entre un 5 y 15% para los encabezados de servicio.
Según la investigación de HTTP Archive, 2025, multipart/form-data se utiliza en el 94% de los casos de carga de archivos en la web. Alternativas: base64 en JSON (4%) y transferencia directa a través de WebSocket (2%). JSON con base64 es conveniente para API donde todos los demás datos también están en JSON, pero es ineficiente para archivos grandes. WebSocket es adecuado para datos en tiempo real, pero no es compatible con todas las infraestructuras HTTP. Multipart sigue siendo el estándar para la carga de archivos debido a su simplicidad y eficiencia.
En aplicaciones móviles, Multipart Upload se utiliza para enviar contenido multimedia desde los dispositivos de los usuarios: fotos de la galería, capturas de cámara, grabaciones de voz, archivos de documentos. En Android, el enfoque estándar es OkHttp con MultipartBody.Builder, que permite formar fácilmente solicitudes multipart. Retrofit también admite multipart mediante las anotaciones @Multipart y @Part. El desarrollador especifica el tipo de datos para cada parte, y el cliente HTTP genera automáticamente los encabezados correctos.
En iOS, las mismas tareas se resuelven con URLSession con un HTTPBodyStream personalizado o mediante Alamofire con multipartFormData. Alamofire proporciona un método conveniente upload(multipartFormData:) para enviar solicitudes multipart. En ambas plataformas, es importante considerar el tamaño de los archivos cargados: para archivos grandes (más de 10-20 MB), se recomienda usar carga en segundo plano para que la aplicación no termine al minimizarse. En Android, esto se hace mediante DownloadManager o WorkManager; en iOS, mediante URLSession con configuración de fondo.
Al cargar archivos en aplicaciones móviles, se debe considerar el estado de la red. Connectivity Manager en Android ayuda a determinar si Wi-Fi o datos móviles están disponibles y elegir el momento óptimo para la carga. Para archivos grandes como videos, se recomienda retrasar la carga hasta que se conecte a Wi-Fi para no consumir los datos móviles del usuario. WorkManager en Android permite configurar tales restricciones a través de NetworkType.UNMETERED.
Antes de enviar un archivo mediante Multipart Upload, las aplicaciones móviles a menudo comprimen y redimensionan la imagen. La compresión JPEG con calidad del 85% reduce el tamaño del archivo de 3 a 5 veces sin pérdida notable de calidad para la visualización en pantalla. Redimensionar la imagen a 1920px en el lado más grande reduce aún más el tamaño. En Android, esto se hace con Bitmap.compress(); en iOS, con UIImageJPEGRepresentation con un parámetro de compresión de 0,85. Dicha optimización acelera la carga y ahorra datos móviles.
El error más común en Multipart Upload es superar el límite de tamaño de solicitud en el servidor. Por defecto, Nginx limita el tamaño del cuerpo de la solicitud a 1 MB (client_max_body_size), y Tomcat a 2 MB (maxSwallowSize). Si el desarrollador no aumenta estos límites, el servidor devuelve un error 413 Request Entity Too Large. La solución es configurar explícitamente el tamaño máximo de carga en el servidor y mostrar una advertencia en el cliente si el archivo supera el tamaño permitido.
El segundo problema es el manejo incorrecto de solicitudes multipart durante la transmisión del cuerpo. Algunos servidores intentan cargar toda la solicitud multipart en memoria antes de analizarla, lo que provoca OutOfMemoryError para archivos grandes. Los servidores modernos (Nginx, Spring Boot, Ktor) admiten el análisis en streaming de multipart, donde cada parte se procesa a medida que llega. El desarrollador debe asegurarse de que el servidor esté configurado para el procesamiento en streaming de solicitudes multipart.
La tercera categoría de problemas son los tiempos de espera al cargar archivos grandes. Los clientes HTTP tienen configuraciones de readTimeout y connectTimeout que pueden activarse durante cargas largas de archivos de más de 50-100 MB. La solución es aumentar los tiempos de espera para los endpoints de carga o usar chunked transfer encoding dentro de multipart. En dispositivos móviles, también es importante manejar la interrupción de la carga e implementar la reanudación (resume) en caso de pérdida de conexión.
La carga de archivos a través de multipart es uno de los endpoints más vulnerables de una aplicación web. Un atacante puede cargar un script ejecutable renombrándolo como image.jpg. El servidor debe verificar el tipo MIME del archivo cargado no por la extensión sino por el contenido (magic bytes), limitar los tipos permitidos y escanear los archivos con un antivirus. Se recomienda almacenar los archivos cargados fuera del document-root del servidor web y servirlos a través de un controlador separado con verificación de permisos de acceso.
Preguntas frecuentes
multipart/form-data transmite cada campo del formulario como un bloque separado con sus propios encabezados y admite archivos binarios sin codificación. application/x-www-form-urlencoded codifica todos los datos en una cadena compatible con URI (clave=valor&clave2=valor2) y no admite archivos directamente: deben codificarse en base64.
El protocolo HTTP no limita el tamaño de una solicitud multipart, pero en la práctica los límites los establece el servidor. Nginx por defecto limita a 1 MB, Apache a 2 MB, Spring Boot a 1 MB. Para cargar archivos grandes, configure client_max_body_size (Nginx) o spring.servlet.multipart.max-file-size (Spring Boot) al valor deseado, por ejemplo, 100 MB.
Sí, multipart/form-data admite múltiples archivos en una sola solicitud. Cada archivo se transmite como una parte separada con su propio Content-Disposition y Content-Type. Los formularios HTML usan el atributo multiple para input type="file". En OkHttp, se llama a addFormDataPart para cada archivo; en Alamofire, se llama a append para cada archivo.
Boundary es una cadena única que separa las partes de una solicitud compuesta y permite al servidor determinar dónde termina una parte y comienza otra. Es generado por el cliente y se especifica en el encabezado Content-Type. Sin un boundary, el servidor no puede analizar una solicitud multicomponente en campos y archivos individuales.
No confíe en la extensión del archivo ni en el Content-Type de la solicitud: un atacante puede falsificarlos. Verifique el tipo MIME mediante magic bytes (los primeros bytes del archivo): Apache Tika en Java, libmagic en C/C++, el comando file en Linux, o herramientas integradas del framework: Files.probeContentType() en Java, mimetypes en Python.
Resumen
Desarrollaremos una aplicación móvil llave en mano
IT Sectr crea aplicaciones para iOS y Android para startups y empresas desde 2017. Le asesoraremos y le propondremos la mejor solución.
Lea también