Saltar al contenido

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

Solución:

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

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 eso ha sido abandonado.

(Otras codificaciones son posibles con solicitudes HTTP generadas por otros medios que no sean el 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 específicos 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:

  • usar multipart/form-data cuando su formulario incluye cualquier <input type="file"> elementos
  • de lo contrario puedes usar multipart/form-data o application/x-www-form-urlencoded pero application/x-www-form-urlencoded será más eficiente

Cuando escribe código del lado del servidor:

  • Utilice una biblioteca de manejo de formularios escritos previamente

La mayoría (como Perl’s CGI->param o el expuesto por PHP $_POST superglobal) se encargará de las diferencias por ti. 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 pueden).


Si está escribiendo (o depurando) una biblioteca para analizar o generar los datos sin procesar, entonces debe comenzar a preocuparse por el formato. Es posible que también desee saberlo por el bien de su interés.

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 es introducido por HTML 5 y es útil solo para depurar – de 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).

cuando debemos usarlo

La respuesta de Quentin es correcta: use multipart/form-data si el formulario contiene una carga de archivo, y application/x-www-form-urlencoded de lo contrario, que es el valor predeterminado si omite enctype.

Voy a:

  • agregue algunas referencias más de HTML5
  • explicar 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 él.

Cómo generar los ejemplos

Una vez que vea un ejemplo de cada método, será obvio cómo funcionan y cuándo debe usar 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 al mínimo .html expediente:

<!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ωb porque ω es U+03C9, que son los bytes 61 CF 89 62 en UTF-8.

Cree 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 'axCFx89b' > binary

Ejecute nuestro pequeño servidor de eco:

while true; do printf '' | nc -l 8000 localhost; 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.

multipart / form-data

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, está claro que:

  • Content-Type: multipart/form-data; boundary=---------------------------735323031399963166993862150 establece el tipo de contenido en multipart/form-data y dice que los campos están separados por el dado boundary cuerda.

    Pero tenga en cuenta que el:

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

    tiene dos papás menos -- que la barrera real

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

    Esto se debe a que el estándar requiere que el límite comience con dos guiones. --. Los otros guiones parecen ser exactamente la forma en que Firefox eligió implementar el límite arbitrario. RFC 7578 menciona claramente que esos dos guiones iniciales -- son requeridos:

    4.1. Parámetro “Límite” de multipart / form-data

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

  • cada campo obtiene algunos subtítulos antes de sus datos: Content-Disposition: form-data;, el campo name, los filename, seguido de los datos.

    El servidor lee los datos hasta la siguiente cadena de límites. 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 la 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. Pregunta en: https://cs.stackexchange.com/questions/39687/find-the-shortest-sequence-that-is-not-a-sub-sequence-of-a-set-of-sequences

  • Content-Type es determinado automáticamente por el navegador.

    ¿Cómo se determina exactamente? Se preguntó en: ¿Cómo determina el navegador el tipo de mímica de un archivo cargado?

application / x-www-form-urlencoded

Ahora cambia el enctype para 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 de 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 tomó 3 bytes cada: %CF%89!

Comparación

Las cargas de archivos a menudo contienen muchos caracteres no imprimibles (por ejemplo, imágenes), mientras que los formularios de texto casi nunca lo hacen.

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 byte.

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

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

Pero para los caracteres imprimibles que se encuentran en los campos de texto, no importa y genera menos sobrecarga, por lo que simplemente lo usamos.

enctype="multipart/form-data es un tipo de codificación que permite enviar archivos a través de un CORREO. Sencillamente, sin esta codificación, los archivos no se pueden enviar a través de CORREO.

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

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *