http - headers - application/x-www-form-urlencoded o multipart/form-data?
http request (6)
En HTTP hay dos formas de POST datos: application/x-www-form-urlencoded
y multipart/form-data
. Entiendo que la mayoría de los navegadores solo pueden cargar archivos si se utiliza multipart/form-data
. ¿Hay alguna guía adicional sobre cuándo usar uno de los tipos de codificación en un contexto de API (sin navegador)? Esto podría, por ejemplo, estar basado en:
- tamaño de datos
- existencia de caracteres no ASCII
- existencia en datos binarios (no codificados)
- la necesidad de transferir datos adicionales (como nombre de archivo)
Básicamente, no he encontrado orientación formal en la web con respecto al uso de los diferentes tipos de contenido hasta el momento.
Solo un pequeño consejo de mi lado para cargar datos de imagen de lienzo HTML5:
Estoy trabajando en un proyecto para una imprenta y tuve algunos problemas debido a la carga de imágenes al servidor que provenía de un elemento de canvas
HTML5. Estuve luchando durante al menos una hora y no pude guardar la imagen correctamente en mi servidor.
Una vez que configuré la opción contentType
de mi llamada jQuery ajax a 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.
¡Tal vez eso ayude a alguien!
Estoy de acuerdo con mucho de lo que ha dicho Manuel. De hecho, sus comentarios se refieren a esta url ...
w3.org/TR/html401/interact/forms.html#h-17.13.4
... Que estados:
El tipo de contenido "application / x-www-form-urlencoded" es ineficaz para enviar grandes cantidades de datos binarios o texto que contiene caracteres no ASCII. El tipo de contenido "multipart / form-data" se debe usar para enviar formularios que contengan archivos, datos que no sean ASCII y datos binarios.
Sin embargo, para mí se reduciría al soporte de herramientas / marco.
- ¿Con qué herramientas y marcos espera que los usuarios de su API construyan sus aplicaciones?
- ¿Tienen marcos o componentes que puedan usar que favorezcan un método sobre el otro?
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, entonces se irán, de lo que dedicará mucho tiempo a respaldarlos.
En segundo lugar, se encuentra la herramienta de soporte que TÚ tienes para escribir tu API y qué tan fácil es para ti acomodar un mecanismo de carga sobre el otro.
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 también es el caso de las aplicaciones web basadas en representaciones HTML típicas (por ejemplo, json payload se hizo muy popular para transmitir cargas útiles para solicitudes ajax).
Respecto a la API Restful sobre HTTP, los tipos de contenido más populares con los que entré en contacto son application / xml y application / json.
aplicación / xml:
- tamaño de datos: XML muy detallado, pero generalmente no es un problema al usar compresión y pensar que el caso de acceso de escritura (por ejemplo, mediante POST o PUT) es mucho más raro como acceso de lectura (en muchos casos es <3% de todo el tráfico ). Rara vez en los casos donde tuve que optimizar el rendimiento de escritura
- existencia de caracteres que no son ASCII: puede usar utf-8 como codificación en XML
- existencia de datos binarios: necesitaría usar la codificación base64
- datos de nombre de archivo: puede encapsular este campo interno en XML
aplicación / json
- tamaño de datos: más compacto que XML, aún texto, pero puede comprimir
- caracteres no ascii: json es utf-8
- datos binarios: base64 (vea también json-binary-question )
- datos de nombre de archivo: encapsular como propia sección de campo dentro de json
Datos binarios como recurso propio.
Intentaría representar datos binarios como activo / recurso propio. Se agrega otra llamada pero se desacopla mejor las cosas. Imágenes de ejemplo:
POST /images
Content-type: multipart/mixed; boundary="xxxx"
... multipart data
201 Created
Location: http://imageserver.org/../foo.jpg
En recursos posteriores, simplemente podría incluir el recurso binario como enlace:
<main-resource>
...
<link href="http://imageserver.org/../foo.jpg"/>
</main-resource>
Si necesita usar Content-Type = x-www-urlencoded-form, NO use FormDataCollection como parámetro: En asp.net Core 2+ FormDataCollection no tiene constructores predeterminados, lo cual es requerido por los formateadores. Utilice IFormCollection en su lugar:
public IActionResult Search([FromForm]IFormCollection type)
{
return Ok();
}
¡LEER POR LO MENOS EL PRIMER 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 de archivo que el servidor finalmente recibe.
Esto no es un problema para application/x-www-form-urlencoded
, porque no hay límite. x-www-form-urlencoded
también puede manejar siempre datos binarios, por el simple recurso de convertir un byte arbitrario en tres bytes de 7 7BIT
. 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 RFC2388 ; la sección 5.2 también incluye una excusa bastante poco convincente para no tener un tipo MIME agregado adecuado que evite este problema).
Entonces, a primera vista, multipart/form-data
tiene ningún valor en ninguna carga de archivo, binario o de otro tipo. Si no elige su límite correctamente, eventualmente tendrá un problema, ya sea que esté enviando texto sin formato o binario sin formato: el servidor encontrará un límite en el lugar equivocado y su archivo se truncará o el POST fallará.
La clave es elegir una codificación y un límite para que los caracteres de los límites 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 un solo =
o un doble ==
. Ahora, elija su límite como una cadena ASCII de 7 bits que no puede aparecer en la salida base64
. Muchas de las opciones que ve en la red fallan en esta prueba: la MDN forma los docs , por ejemplo, usa "blob" como límite al enviar datos binarios, no es bueno. Sin embargo, algo como "! Blob!" Nunca aparecerá en la salida base64
.
TL; DR
Resumen; Si tiene datos binarios (no alfanuméricos) (o una carga útil de tamaño significativo) para transmitir, use multipart/form-data
. De lo contrario, use application/x-www-form-urlencoded
.
Los tipos MIME que menciona son los dos encabezados de Content-Type
para las solicitudes POST de HTTP que los agentes de usuario (exploradores) 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é, tienes que mirar lo que cada uno está haciendo debajo de las portadas.
Para application/x-www-form-urlencoded
, el cuerpo del mensaje HTTP enviado al servidor es esencialmente una cadena de consulta gigante: los pares nombre / valor están separados por el signo ( &
), y los nombres están separados de los valores por el símbolo es igual al símbolo ( =
). Un ejemplo de esto sería:
MyVariableOne=ValueOne&MyVariableTwo=ValueTwo
Según la specification :
Los caracteres [reservados y] no alfanuméricos se reemplazan por `% HH '', un signo de porcentaje y dos dígitos hexadecimales que representan el código ASCII del carácter
Eso significa que para cada byte no alfanumérico que existe en uno de nuestros valores, tomará tres bytes para representarlo. Para archivos binarios grandes, triplicar la carga útil será altamente ineficiente.
Ahí es donde entra en multipart/form-data
. Con este método de transmisión de 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 se produzca en ninguna de las cargas útiles de "valor"). Cada parte tiene su propio conjunto de encabezados MIME como Content-Type
, y particularmente Content-Disposition
, que puede dar a cada parte su "nombre". La pieza de valor de cada par de nombre / valor es la carga útil de cada parte del mensaje MIME. La especificación MIME nos brinda más opciones al representar el valor de la carga útil: 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 superará significativamente cualquier ahorro de una codificación binaria más eficiente.