¿Qué significa enctype='multipart/form-data'?
¿Qué enctype='multipart/form-data'
significa en un formulario HTML y cuándo debemos usarlo?
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-data
cuando su formulario incluya algún<input type="file">
elemento - de lo contrario puedes usar
multipart/form-data
oapplication/x-www-form-urlencoded
peroapplication/x-www-form-urlencoded
será 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->param
o el expuesto por $_POST
superglobal 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-urlencoded
es más o menos lo mismo que una cadena de consulta al final de la URL.
multipart/form-data
Es 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/plain
se 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).
¿Cuándo debemos usarlo?
La respuesta de Quentin es correcta: úselo multipart/form-data
si el formulario contiene una carga de archivo y, application/x-www-form-urlencoded
en 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 -l
o 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 .html
archivo 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ω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ωb
, lo que significa aωb
porque ω
es U+03C9
, que son los bytes 61 CF 89 62
en 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.
nc
imprime la solicitud recibida.
Probado en: Ubuntu 14.04.3, nc
BSD 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ωb
en 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=---------------------------735323031399963166993862150
establece el tipo de contenidomultipart/form-data
y dice que los campos están separados por laboundary
cadena 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 camponame
, elfilename
seguido 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-sequencesContent-Type
lo 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-urlencoded
vuelva 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 a
y b
se enviaron en un byte, mientras que los no imprimibles como 0xCF
y 0x89
ocuparon 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-data
es 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 .
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 POST
o GET
métodos HTTP .
POST
le 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).GET
enviará 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 enctype
tiene sentido sólo cuando se utiliza POST
el 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.
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-data
se utiliza cuando un formulario requiere que se carguen datos binarios, como el contenido de un archivo.