En HTTP hay dos formas de enviar datos: application/x-www-form-urlencoded
y multipart/form-data
. Entiendo que la mayoría de los navegadores solo pueden cargar archivos si multipart/form-data
se usan. ¿Hay alguna guía adicional sobre cuándo usar uno de los tipos de codificación en un contexto API (sin navegador involucrado)? Esto podría, por ejemplo, basarse en:
- tamaño de datos
- existencia de caracteres no ASCII
- existencia en datos binarios (sin codificar)
- la necesidad de transferir datos adicionales (como nombre de archivo)
Básicamente no encontré ninguna guía formal en la web con respecto al uso de los diferentes tipos de contenido hasta ahora.
http
post
http-headers
max
fuente
fuente
Respuestas:
TL; DR
Resumen; si tiene datos binarios (no alfanuméricos) (o una carga útil de tamaño significativo) para transmitir, utilícelos
multipart/form-data
. De lo contrario, useapplication/x-www-form-urlencoded
.Los tipos MIME que menciona son los dos
Content-Type
encabezados para las solicitudes HTTP POST que los agentes de usuario (navegadores) deben admitir. El propósito de ambos tipos de solicitudes es enviar una lista de pares de nombre / valor al servidor. Dependiendo del tipo y la cantidad de datos que se transmiten, uno de los métodos será más eficiente que el otro. Para entender por qué, debes mirar lo que cada uno está haciendo debajo de las sábanas.Porque
application/x-www-form-urlencoded
, el cuerpo del mensaje HTTP enviado al servidor es esencialmente una cadena de consulta gigante: los pares de nombre / valor están separados por el signo y (&
), y los nombres están separados de los valores por el símbolo de igual (=
). Un ejemplo de esto sería:MyVariableOne=ValueOne&MyVariableTwo=ValueTwo
De acuerdo con la especificación :
Eso significa que por cada byte no alfanumérico que existe en uno de nuestros valores, se necesitarán tres bytes para representarlo. Para archivos binarios grandes, triplicar la carga útil será muy ineficiente.
Ahí es donde
multipart/form-data
entra. Con este método de transmitir pares de nombre / valor, cada par se representa como una "parte" en un mensaje MIME (como se describe en otras respuestas). Las partes están separadas por un límite de cadena particular (elegido específicamente para que esta cadena de límite no aparezca en ninguna de las cargas útiles de "valor"). Cada parte tiene su propio conjunto de encabezados MIME comoContent-Type
, y en particularContent-Disposition
, que puede dar a cada parte su "nombre". La pieza de valor de cada par nombre / valor es la carga útil de cada parte del mensaje MIME. La especificación MIME nos brinda más opciones al representar la carga útil del valor: podemos elegir una codificación más eficiente de datos binarios para ahorrar ancho de banda (por ejemplo, base 64 o incluso binario sin formato).¿Por qué no usar
multipart/form-data
todo el tiempo? Para valores alfanuméricos cortos (como la mayoría de los formularios web), la sobrecarga de agregar todos los encabezados MIME va a superar significativamente cualquier ahorro de una codificación binaria más eficiente.fuente
¡LEA AL MENOS EL PRIMERO PARA AQUÍ!
Sé que esto es 3 años demasiado tarde, pero la respuesta de Matt (aceptada) es incompleta y eventualmente te meterá en problemas. La clave aquí es que, si elige usar
multipart/form-data
, el límite no debe aparecer en los datos del archivo que el servidor finalmente recibe.Esto no es un problema
application/x-www-form-urlencoded
, porque no hay límite.x-www-form-urlencoded
También siempre puede manejar datos binarios, por el simple recurso de convertir un byte arbitrario en tres7BIT
bytes. Ineficiente, pero funciona (y tenga en cuenta que el comentario sobre no poder enviar nombres de archivos y datos binarios es incorrecto; simplemente lo envía como otro par clave / valor).El problema con
multipart/form-data
es que el separador de límites no debe estar presente en los datos del archivo (consulte RFC 2388 ; la sección 5.2 también incluye una excusa poco convincente para no tener un tipo MIME agregado adecuado que evite este problema).Entonces, a primera vista, no
multipart/form-data
tiene ningún valor en la carga de ningún archivo, binario o de otro tipo. Si no elige su límite correctamente, entonces usted va a llegar a tener un problema, si va a enviar texto o binario - el servidor se encuentra un límite en el lugar equivocado, y el archivo se truncará, o el POST fallará.La clave es elegir una codificación y un límite de modo que los caracteres de límite seleccionados no puedan aparecer en la salida codificada. Una solución simple es usar
base64
( no usar binario sin formato). En base64, 3 bytes arbitrarios se codifican en cuatro caracteres de 7 bits, donde el conjunto de caracteres de salida es[A-Za-z0-9+/=]
( es decir, alfanuméricos, '+', '/' o '=').=
es un caso especial y solo puede aparecer al final de la salida codificada, como simple=
o doble==
. Ahora, elija su límite como una cadena ASCII de 7 bits que no puede aparecer en labase64
salida. Muchas de las opciones que ve en la red no pasan esta prueba: el MDN forma documentos, por ejemplo, use "blob" como límite cuando envíe datos binarios, lo cual no es bueno. Sin embargo, algo como "! Blob!" nunca aparecerá en labase64
salida.fuente
index === -1
.'()+-./:=
entonces. Sin embargo, la generación aleatoria con subcadena cheque sigue siendo el camino a seguir y que se puede hacer con una sola línea:while(true){r = rand(); if(data.indexOf(r) === -1){doStuff();break;}}
. La sugerencia de EML (convertir a base64 solo para evitar subcadenas coincidentes) es simplemente extraña, sin mencionar que viene con una degradación innecesaria del rendimiento. Y todo el problema por nada ya que el algoritmo de una línea es igualmente sencillo y simple. No se pretende que Base64 se use (ab) de esta manera, ya que el cuerpo HTTP acepta todos los octetos de 8 bits .No creo que HTTP esté limitado a POST en multiparte o x-www-form-urlencoded. El Encabezado de tipo de contenido es ortogonal al método HTTP POST (puede completar el tipo MIME que más le convenga). Este es también el caso de las aplicaciones web típicas basadas en representación HTML (por ejemplo, la carga útil json se hizo muy popular para transmitir la carga útil para las solicitudes ajax).
Con respecto a Restful API sobre HTTP, los tipos de contenido más populares con los que contacté son application / xml y application / json.
aplicación / xml:
aplicación / json
datos binarios como recurso propio
Intentaría representar los datos binarios como un activo / recurso propio. Agrega otra llamada pero desacopla mejor las cosas. Imágenes de ejemplo:
En recursos posteriores, podría simplemente insertar el recurso binario como enlace:
fuente
Estoy de acuerdo con mucho de lo que ha dicho Manuel. De hecho, sus comentarios se refieren a esta url ...
http://www.w3.org/TR/html401/interact/forms.html#h-17.13.4
... Que estados:
Sin embargo, para mí todo se reduciría al soporte de herramientas / marcos.
Si tiene una idea clara de sus usuarios y cómo utilizarán su API, eso lo ayudará a decidir. Si dificulta la carga de archivos para los usuarios de su API, se alejarán, de lo que pasará mucho tiempo dándoles soporte.
Secundario a esto sería el soporte de herramientas que USTED tiene para escribir su API y lo fácil que es para usted acomodar un mecanismo de carga sobre el otro.
fuente
Solo una pequeña pista de mi parte para cargar datos de imágenes de lienzo HTML5:
Estoy trabajando en un proyecto para una imprenta y tuve algunos problemas debido a la carga de imágenes en el servidor que provenían de un
canvas
elemento HTML5 . Estuve luchando durante al menos una hora y no pude guardar la imagen correctamente en mi servidor.Una vez que configuré la
contentType
opción de mi llamada jQuery ajax,application/x-www-form-urlencoded
todo salió bien y los datos codificados en base64 se interpretaron correctamente y se guardaron con éxito como una imagen.¡Quizás eso ayude a alguien!
fuente
Si necesita usar Content-Type = x-www-urlencoded-form, entonces NO use FormDataCollection como parámetro: en asp.net Core 2+ FormDataCollection no tiene constructores predeterminados que requieren los formateadores. Utilice IFormCollection en su lugar:
fuente