Cuando envío un formulario simple como este con un archivo adjunto:
<form enctype="multipart/form-data" action="http://localhost:3000/upload?upload_progress_id=12344" method="POST">
<input type="hidden" name="MAX_FILE_SIZE" value="100000" />
Choose a file to upload: <input name="uploadedfile" type="file" /><br />
<input type="submit" value="Upload File" />
</form>
¿Cómo se envía el archivo internamente? ¿El archivo se envía como parte del cuerpo HTTP como datos? En los encabezados de esta solicitud, no veo nada relacionado con el nombre del archivo.
Solo me gustaría saber el funcionamiento interno de HTTP al enviar un archivo.
http
file-upload
0xSina
fuente
fuente
MAX_FILE_SIZE
en PHP - cuál es el punto" en stackoverflow.com/q/1381364/632951Respuestas:
Echemos un vistazo a lo que sucede cuando selecciona un archivo y envía su formulario (he truncado los encabezados por brevedad):
NOTA: cada cadena de límite debe tener como prefijo un extra
--
, al igual que al final de la última cadena de límite. El ejemplo anterior ya incluye esto, pero puede ser fácil pasarlo por alto. Ver comentario de @Andreas a continuación.En lugar de codificar la URL de los parámetros del formulario, los parámetros del formulario (incluidos los datos del archivo) se envían como secciones en un documento de varias partes en el cuerpo de la solicitud.
En el ejemplo anterior, puede ver la entrada
MAX_FILE_SIZE
con el valor establecido en el formulario, así como una sección que contiene los datos del archivo. El nombre del archivo es parte delContent-Disposition
encabezado.Los detalles completos están aquí .
fuente
Se llama al formato
multipart/form-data
, como se pregunta en: ¿Qué significa enctype = 'multipart / form-data'?Voy a:
Referencias HTML5
Hay tres posibilidades para
enctype
:x-www-urlencoded
multipart/form-data
(puntos de especificación a RFC2388 )text-plain
. Esto "no se puede interpretar de manera confiable por computadora", por lo que nunca se debe usar en producción, y no lo analizaremos más a fondo.¿Cómo generar los ejemplos?
Una vez que vea un ejemplo de cada método, se hace evidente 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 / POSTGuarde el formulario en un
.html
archivo mínimo :Establecemos el valor de texto predeterminado en
aωb
, lo que significaaωb
porqueω
esU+03C9
, que son los bytes61 CF 89 62
en UTF-8.Crear archivos para cargar:
Ejecute nuestro pequeño servidor echo:
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ó:
Para el archivo binario y el campo de texto, los bytes
61 CF 89 62
(aωb
en UTF-8) se envían literalmente. Puede verificar eso connc -l localhost 8000 | hd
, que dice que los bytes:fueron enviados (
61
== 'a' y62
== 'b').Por lo tanto, está 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 el dadoboundary
cadena .Pero tenga en cuenta que el:
tiene dos papas menos
--
que la barrera realEsto se debe a que el estándar requiere que el límite comience con dos guiones
--
. Los otros guiones parecen ser exactamente cómo Firefox eligió implementar el límite arbitrario. RFC 7578 menciona claramente que--
se requieren esos dos guiones iniciales:cada campo obtiene algunos subtítulos antes de sus datos:
Content-Disposition: form-data;
el camponame
, elfilename
, seguido de los datos.El servidor lee los datos hasta la siguiente cadena de límite. El navegador debe elegir un límite que no aparecerá en ninguno de los campos, por lo que el límite puede variar entre las 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? Preguntado en: /cs/39687/find-the-shortest-sequence-that-is-not-a-sub-sequence-of-a-set-of-sequencesContent-Type
se determina automáticamente por el navegador.Se preguntó cómo se determina exactamente en: ¿Cómo se determina el tipo mime de un archivo cargado por el navegador?
application / x-www-form-urlencoded
Ahora cambie
enctype
aapplication/x-www-form-urlencoded
, vuelva a cargar el navegador y vuelva a enviar.Firefox envió:
Claramente, los datos del archivo no se enviaron, solo los nombres básicos. Por lo tanto, esto no se puede usar para archivos.
En cuanto al campo de texto, vemos que a los caracteres imprimibles habituales les gusta
a
yb
se enviaron en un byte, mientras que a los no imprimibles les gusta0xCF
y0x89
ocupaban 3 bytes cada uno%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 unos pocos bytes de sobrecarga de límite al mensaje, y debe pasar algún tiempo calculándolo, 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 factor de sobrecarga lineal de 3x por 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 sobrecarga, por lo que solo lo usamos.
fuente
Content-Disposition
yContent-Type
pero cómo manejar el 'contenido'?Enviar archivo como contenido binario (cargar sin formulario o FormData)
En las respuestas / ejemplos dados, el archivo se carga (muy probablemente) con un formulario HTML o con la API FormData . El archivo es solo una parte de los datos enviados en la solicitud, de ahí el
multipart/form-data
Content-Type
encabezado.Si desea enviar el archivo como el único contenido, puede agregarlo directamente como el cuerpo de la solicitud y establecer el
Content-Type
encabezado con el tipo MIME del archivo que está enviando. El nombre del archivo se puede agregar en elContent-Disposition
encabezado. Puedes subir así:Si no (desea) usar formularios y solo está interesado en cargar un solo archivo, esta es la forma más fácil de incluir su archivo en la solicitud.
fuente
Content-Type
del encabezado.Tengo este código Java de muestra:
y tengo este archivo test.html:
y finalmente el archivo que usaré para fines de prueba, llamado a.dat, tiene el siguiente contenido:
si interpreta los bytes anteriores como caracteres ASCII o UTF-8, en realidad representarán:
Así que ejecutemos nuestro Código Java, abra test.html en nuestro navegador favorito, cargue
a.dat
y envíe el formulario y vea lo que recibe nuestro servidor:Bueno, no me sorprende ver a los personajes 9ie porque le dijimos a Java que los imprimiera tratándolos como personajes UTF-8. También puede optar por leerlos como bytes sin procesar.
es en realidad el último encabezado HTTP aquí. Después de eso viene el Cuerpo HTTP, donde se pueden ver meta y contenidos del archivo que subimos.
fuente
http://www.tutorialspoint.com/http/http_messages.htm
fuente