Pregunta application / x-www-form-urlencoded o multipart / form-data?


En HTTP hay dos formas de publicar 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 es usado. ¿Hay alguna guía adicional sobre cuándo usar uno de los tipos de codificación en un contexto de API (sin navegador involucrado)? Esto podría, p. Ej. 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 encontré ninguna guía formal en la web sobre el uso de los diferentes tipos de contenido hasta el momento.


1066
2017-10-24 11:12


origen


Respuestas:


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 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. Según el tipo y la cantidad de datos que se transmitan, 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.

por 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 (&), y los nombres están separados de los valores por el símbolo de igualdad (=) Un ejemplo de esto sería:

MyVariableOne=ValueOne&MyVariableTwo=ValueTwo

De acuerdo con la especificación:

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 personaje

Eso significa que para cada byte no alfanumérico que existe en uno de nuestros valores, va a tomar 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 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-Typey particularmente Content-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 cuando representamos 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 en bruto).

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.


1666
2017-11-01 21:59



¡LEA AL MENOS EL PRIMERO PARA AQUÍ!

Sé que esto es 3 años 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 debe no aparecer en los datos del archivo que el servidor finalmente recibe.

Esto no es un problema para application/x-www-form-urlencodedporque no hay límite. x-www-form-urlencoded también puede manejar datos binarios, por el simple hecho de convertir un byte arbitrario en tres 7BIT bytes. Ineficiente, pero funciona (y tenga en cuenta que el comentario sobre no poder enviar nombres de archivo así como datos binarios es incorrecto; solo 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 (ver RFC2388; la sección 5.2 también incluye una excusa bastante poco convincente para no tener un tipo MIME agregado apropiado que evite este problema).

Entonces, a primera vista, multipart/form-data no tiene ningún valor en absoluto alguna carga de archivos, binarios o de otro tipo. Si no elige su límite correctamente, entonces será finalmente tendrá un problema, ya sea que esté enviando texto sin formato o binario en bruto: el servidor encontrará un límite en el lugar equivocado, y su archivo se truncará, o la POST fallará.

La clave es elegir una codificación y un límite tal que los caracteres de límite seleccionados no puedan aparecer en la salida codificada. Una solución simple es usar base64 (hacer no usar binario sin procesar). En base64 3 bytes arbitrarios están codificados 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 puede aparecer solo 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 base64 salida. Muchas opciones que ve en la red no pasan esta prueba: las formas MDN documentos, por ejemplo, use "blob" como límite al enviar datos binarios, no es bueno. Sin embargo, algo así como "! Blob!" nunca aparecerá en base64 salida.


106
2018-04-18 11:08



No creo que HTTP esté limitado a POST en multipart o x-www-form-urlencoded. los Encabezado de tipo de contenido es ortogonal al método HTTP POST (puede completar el tipo MIME que le convenga). Este es también el caso de las típicas aplicaciones basadas en representación HTML (por ejemplo, la carga útil json se volvió muy popular para transmitir la carga útil para solicitudes ajax).

Con respecto a Restful API sobre HTTP, los tipos de contenido más populares con los que me puse en contacto son application / xml y application / json.

aplicación / xml:

  • data-size: XML muy detallado, pero generalmente no es un problema cuando se usa compresión y pensando que el caso de acceso de escritura (por ejemplo, a través de POST o PUT) es mucho más raro como acceso de lectura (en muchos casos es <3% de todo el tráfico) ) Rara vez hay casos en los que tuve que optimizar el rendimiento de escritura
  • existencia de caracteres no ascii: puede usar utf-8 como codificación en XML
  • existencia de datos binarios: necesitaría usar 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 menos que XML, aún texto, pero puede comprimir
  • caracteres no ascii: json es utf-8
  • datos binarios: base64 (ver también json-binary-question)
  • datos de nombre de archivo: encapsular como propia sección de campo dentro de json

datos binarios como recursos propios

Intentaría representar datos binarios como un activo / recurso propio. Agrega otra llamada pero desacopla las cosas mejor. 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 puede alinear el recurso binario como un enlace:

<main-resource>
 ...
 <link href="http://imageserver.org/../foo.jpg"/>
</main-resource>

82
2017-10-24 16:46



Estoy de acuerdo con mucho de lo que Manuel ha dicho. De hecho, sus comentarios se refieren a esta url ...

http://www.w3.org/TR/html401/interact/forms.html#h-17.13.4

... Que estados:

El tipo de contenido   "application / x-www-form-urlencoded" es   ineficiente para enviar grandes   cantidades de datos binarios o texto   que contiene caracteres que no son ASCII. los   tipo de contenido "multipart / form-data"   se debe usar para enviar formularios   que contienen archivos, datos que no son ASCII,   y datos binarios.

Sin embargo, para mí todo se reduciría al soporte de herramientas / marcos.

  • ¿Qué herramientas y marcos tienes? espera que tus usuarios de API estén construyendo sus aplicaciones con?
  • Tienen ellos marcos o componentes que pueden usar que favorecen un método sobre el ¿otro?

Si tiene una idea clara de sus usuarios y cómo harán uso de su API, eso lo ayudará a decidir. Si haces que la carga de archivos sea difícil para tus usuarios de API, se irán, y pasarás mucho tiempo apoyándolos.

Secundario a esto sería la herramienta que USTED tiene para escribir su API y lo fácil que es para usted acomodar un mecanismo de carga sobre el otro.


26
2017-10-27 12:08



Solo un pequeño consejo de mi parte para subir datos de imágenes de canvas 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 HTML5 canvas elemento. Estuve luchando durante al menos una hora y no pude guardar la imagen correctamente en mi servidor.

Una vez que configuro el contentType opción de mi jQuery ajax llamada a application/x-www-form-urlencoded todo fue bien y los datos codificados en base64 se interpretaron correctamente y se guardaron correctamente como una imagen.


Tal vez eso ayude a alguien!


0
2017-12-10 15:07