¿Qué significa enctype='multipart/form-data'?

Resuelto EBAG asked hace 13 años • 9 respuestas

¿Qué enctype='multipart/form-data'significa en un formulario HTML y cuándo debemos usarlo?

EBAG avatar Dec 24 '10 19:12 EBAG
Aceptado

Cuando realiza una solicitud POST, debe codificar de alguna manera los datos que forman el cuerpo de la solicitud.

Los formularios HTML proporcionan tres métodos de codificación .

  • application/x-www-form-urlencoded(el valor por defecto)
  • multipart/form-data
  • text/plain

Se estaba trabajando para agregar application/json, pero se abandonó.

(Son posibles otras codificaciones con solicitudes HTTP generadas utilizando otros medios además del envío de un formulario HTML. JSON es un formato común para usar con servicios web y algunos todavía usan SOAP).

Los detalles de los formatos no son importantes para la mayoría de los desarrolladores. Los puntos importantes son:

  • Nunca usar text/plain.

Cuando escribe código del lado del cliente:

  • Úselo multipart/form-datacuando su formulario incluya algún <input type="file">elemento
  • de lo contrario puedes usar multipart/form-datao application/x-www-form-urlencodedpero application/x-www-form-urlencodedserá más eficiente

Cuando escribe código del lado del servidor:

  • Utilice una biblioteca de manejo de formularios preescritos

La mayoría (como Perl CGI->paramo el expuesto por $_POSTsuperglobal de PHP) se encargarán de las diferencias por usted. No se moleste en intentar analizar la entrada sin procesar recibida por el servidor.

A veces encontrará una biblioteca que no puede manejar ambos formatos. La biblioteca más popular de Node.js para manejar datos de formularios es body-parser que no puede manejar solicitudes de varias partes (pero tiene documentación que recomienda algunas alternativas que sí pueden hacerlo).


Si está escribiendo (o depurando) una biblioteca para analizar o generar datos sin procesar, entonces debe comenzar a preocuparse por el formato. Quizás también quieras saberlo por si acaso.

application/x-www-form-urlencodedes más o menos lo mismo que una cadena de consulta al final de la URL.

multipart/form-dataEs significativamente más complicado pero permite incluir archivos completos en los datos. Se puede encontrar un ejemplo del resultado en la especificación HTML 4 .

text/plainse introduce en HTML 5 y es útil solo para depurar, según la especificación : no son interpretables de manera confiable por computadora , y yo diría que los otros combinados con herramientas (como el Panel de red en las herramientas de desarrollo de la mayoría de los navegadores) son mejores. para eso).

Quentin avatar Dec 24 '2010 12:12 Quentin

¿Cuándo debemos usarlo?

La respuesta de Quentin es correcta: úselo multipart/form-datasi el formulario contiene una carga de archivo y, application/x-www-form-urlencodeden caso contrario, que es el valor predeterminado si omite enctype.

Voy a:

  • agregue algunas referencias HTML5 más
  • explique por qué tiene razón con un ejemplo de envío de formulario

Referencias HTML5

Hay tres posibilidades para enctype:

  • application/x-www-form-urlencoded
  • multipart/form-data(la especificación apunta a RFC7578 )
  • text/plain. Esto "no es interpretable de manera confiable por computadora", por lo que nunca debe usarse en producción y no profundizaremos en ello.

Cómo generar los ejemplos.

Una vez que vea un ejemplo de cada método, resultará obvio cómo funcionan y cuándo debe utilizar cada uno.

Puede producir ejemplos usando:

  • nc -lo un servidor ECHO: servidor de prueba HTTP que acepta solicitudes GET/POST
  • un agente de usuario como un navegador o cURL

Guarde el formulario en un .htmlarchivo mínimo:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8"/>
  <title>upload</title>
</head>
<body>
<form action="http://localhost:8000" method="post" enctype="multipart/form-data">
  <p><input type="text" name="text1" value="text default">
  <p><input type="text" name="text2" value="a&#x03C9;b">
  <p><input type="file" name="file1">
  <p><input type="file" name="file2">
  <p><input type="file" name="file3">
  <p><button type="submit">Submit</button>
</form>
</body>
</html>

Establecemos el valor de texto predeterminado en a&#x03C9;b, lo que significa aωbporque ωes U+03C9, que son los bytes 61 CF 89 62en UTF-8.

Crea archivos para cargar:

echo 'Content of a.txt.' > a.txt

echo '<!DOCTYPE html><title>Content of a.html.</title>' > a.html

# Binary file containing 4 bytes: 'a', 1, 2 and 'b'.
printf 'a\xCF\x89b' > binary

Ejecute nuestro pequeño servidor de eco:

while true; do printf '' | nc -l localhost 8000; done

Abra el HTML en su navegador, seleccione los archivos y haga clic en enviar y verifique el terminal.

ncimprime la solicitud recibida.

Probado en: Ubuntu 14.04.3, ncBSD 1.105, Firefox 40.

datos multiparte/formulario

Firefox envió:

POST / HTTP/1.1
[[ Less interesting headers ... ]]
Content-Type: multipart/form-data; boundary=---------------------------735323031399963166993862150
Content-Length: 834

-----------------------------735323031399963166993862150
Content-Disposition: form-data; name="text1"

text default
-----------------------------735323031399963166993862150
Content-Disposition: form-data; name="text2"

aωb
-----------------------------735323031399963166993862150
Content-Disposition: form-data; name="file1"; filename="a.txt"
Content-Type: text/plain

Content of a.txt.

-----------------------------735323031399963166993862150
Content-Disposition: form-data; name="file2"; filename="a.html"
Content-Type: text/html

<!DOCTYPE html><title>Content of a.html.</title>

-----------------------------735323031399963166993862150
Content-Disposition: form-data; name="file3"; filename="binary"
Content-Type: application/octet-stream

aωb
-----------------------------735323031399963166993862150--

Para el archivo binario y el campo de texto, los bytes 61 CF 89 62( aωben UTF-8) se envían literalmente. Podrías verificar eso con nc -l localhost 8000 | hd, que dice que los bytes:

61 CF 89 62

fueron enviados ( 61== 'a' y 62== 'b').

Por tanto queda claro que:

  • Content-Type: multipart/form-data; boundary=---------------------------735323031399963166993862150establece el tipo de contenido multipart/form-datay dice que los campos están separados por la boundarycadena dada.

    Pero tenga en cuenta que:

    boundary=---------------------------735323031399963166993862150
    

    tiene dos guiones menos --que la barrera real

    -----------------------------735323031399963166993862150
    

    Esto se debe a que la norma requiere que el límite comience con dos guiones --. Los otros guiones parecen ser la forma en que Firefox decidió implementar el límite arbitrario. RFC 7578 menciona claramente que esos dos guiones iniciales --son necesarios:

    4.1. Parámetro "límite" de datos multiparte/formulario

    Al igual que con otros tipos multiparte, las partes se delimitan con un delimitador de límite, construido utilizando CRLF, "--" y el valor del parámetro "límite".

  • Cada campo tiene algunos subencabezados antes de sus datos: Content-Disposition: form-data;el campo name, el filenameseguido de los datos.

    El servidor lee los datos hasta la siguiente cadena límite. El navegador debe elegir un límite que no aparecerá en ninguno de los campos, por eso el límite puede variar entre solicitudes.

    Debido a que tenemos el límite único, no es necesaria ninguna codificación de los datos: los datos binarios se envían tal cual.

    TODO: ¿cuál es el tamaño de límite óptimo ( log(N)apuesto) y el nombre/tiempo de ejecución del algoritmo que lo encuentra? Preguntado en: https://cs.stackexchange.com/questions/39687/find-the-shortest-sequence-that-is-not-a-sub-sequence-of-a-set-of-sequences

  • Content-Typelo determina automáticamente el navegador.

    Se preguntó cómo se determina exactamente en: ¿ Cómo determina el navegador el tipo mime de un archivo cargado?

aplicación/x-www-formulario-urlencoded

Ahora cambie a enctype, application/x-www-form-urlencodedvuelva a cargar el navegador y vuelva a enviarlo.

Firefox envió:

POST / HTTP/1.1
[[ Less interesting headers ... ]]
Content-Type: application/x-www-form-urlencoded
Content-Length: 51

text1=text+default&text2=a%CF%89b&file1=a.txt&file2=a.html&file3=binary

Claramente, los datos del archivo no se enviaron, solo los nombres base. Entonces esto no se puede usar para archivos.

En cuanto al campo de texto, vemos que los caracteres imprimibles habituales como ay bse enviaron en un byte, mientras que los no imprimibles como 0xCFy 0x89ocuparon 3 bytes cada uno: %CF%89!

Comparación

Los archivos cargados suelen contener muchos caracteres no imprimibles (por ejemplo, imágenes), mientras que los formularios de texto casi nunca los contienen.

De los ejemplos hemos visto que:

  • multipart/form-data: agrega algunos bytes de sobrecarga de límites al mensaje y debe dedicar algún tiempo a calcularlo, pero envía cada byte en un solo byte.

  • application/x-www-form-urlencoded: tiene un límite de un solo byte por campo ( &), pero agrega un factor de sobrecarga lineal de 3x para cada carácter no imprimible.

Por lo tanto, incluso si pudiéramos enviar archivos con application/x-www-form-urlencoded, no querríamos hacerlo, porque es muy ineficiente.

Pero para los caracteres imprimibles que se encuentran en los campos de texto, no importa y genera menos gastos generales, así que simplemente lo usamos.

enctype='multipart/form-dataes un tipo de codificación que permite enviar archivos a través de un POST . Sencillamente, sin esta codificación los archivos no se pueden enviar mediante POST .

Si desea permitir que un usuario cargue un archivo a través de un formulario, debe usar este enctype .

Matt Asbury avatar Dec 24 '2010 12:12 Matt Asbury

Al enviar un formulario, le indica a su navegador que envíe, a través del protocolo HTTP, un mensaje en la red, debidamente envuelto en una estructura de mensaje del protocolo TCP/IP. Una página HTML tiene una forma de enviar datos al servidor: mediante <form>s.

Cuando se envía un formulario, se crea una solicitud HTTP y se envía al servidor; el mensaje contendrá los nombres de los campos en el formulario y los valores completados por el usuario. Esta transmisión puede ocurrir con POSTo GET métodos HTTP .

  • POSTle dice a su navegador que cree un mensaje HTTP y coloque todo el contenido en el cuerpo del mensaje (una forma muy útil de hacer las cosas, más segura y también flexible).
  • GETenviará los datos del formulario en la cadena de consulta . Tiene algunas limitaciones sobre la representación y la longitud de los datos.

Indicando cómo enviar su formulario al servidor

El atributo enctypetiene sentido sólo cuando se utiliza POSTel método. Cuando se especifica, indica al navegador que envíe el formulario codificando su contenido de una manera específica. Desde MDN - Tipo de formulario :

Cuando el valor del atributo del método es post, enctype es el tipo de contenido MIME que se utiliza para enviar el formulario al servidor.

  • application/x-www-form-urlencoded: Este es el valor predeterminado. Cuando se envía el formulario, se recopilan todos los nombres y valores y se realiza la codificación de URL en la cadena final.
  • multipart/form-data: Los caracteres NO están codificados. Esto es importante cuando el formulario tiene un control de carga de archivos. Desea enviar el archivo binario y esto garantiza que el flujo de bits no se modifique.
  • text/plain: Los espacios se convierten, pero no se realiza más codificación.

Seguridad

Al enviar formularios, pueden surgir algunos problemas de seguridad, como se indica en RFC 7578 Sección 7: Datos de formularios de varias partes - Consideraciones de seguridad :

Todo software de procesamiento de formularios debe tratar los datos de formulario proporcionados por el usuario
con sensibilidad, ya que a menudo contienen
información confidencial o de identificación personal. Existe un uso generalizado de funciones de "autocompletar" de formularios en los navegadores web; Estos podrían usarse para engañar a los usuarios para que,
sin saberlo, envíen información confidencial al realizar
tareas que de otro modo serían inocuas. multipart/form-data no proporciona ninguna función
para verificar la integridad, garantizar la confidencialidad, evitar
la confusión del usuario u otras funciones de seguridad; esas preocupaciones deben ser
abordadas por las aplicaciones de llenado de formularios e interpretación de datos de formularios.

Las aplicaciones que reciben formularios y los procesan deben tener cuidado de no proporcionar al sitio de procesamiento de formularios datos que no estaban destinados a ser enviados.

Es importante al interpretar el nombre de archivo del
campo de encabezado Content-Disposition no sobrescribir inadvertidamente archivos en el
espacio de archivos del destinatario.

Esto le concierne si es desarrollador y su servidor procesará formularios enviados por los usuarios que podrían terminar conteniendo información confidencial.

Andry avatar Dec 24 '2010 17:12 Andry

enctype='multipart/form-data'significa que no se codificarán caracteres. es por eso que este tipo se utiliza al cargar archivos al servidor.
So multipart/form-datase utiliza cuando un formulario requiere que se carguen datos binarios, como el contenido de un archivo.

GP Singh avatar Jul 04 '2013 09:07 GP Singh