Question application / x-www-form-urlencoded ou multipart / form-data?


Dans HTTP, il existe deux façons de générer des données POST: application/x-www-form-urlencoded et multipart/form-data. Je comprends que la plupart des navigateurs ne peuvent télécharger des fichiers que si multipart/form-data est utilisé. Existe-t-il des indications supplémentaires pour utiliser l'un des types d'encodage dans un contexte API (sans navigateur)? Cela pourrait par exemple être basé sur:

  • taille des données
  • existence de caractères non-ASCII
  • existence sur des données binaires (non codées)
  • la nécessité de transférer des données supplémentaires (comme le nom de fichier)

Pour l'essentiel, je n'ai trouvé aucune directive officielle sur le Web concernant l'utilisation des différents types de contenu jusqu'à présent.


1066
2017-10-24 11:12


origine


Réponses:


TL; DR

Résumé; Si vous avez des données binaires (non alphanumériques) (ou une charge utile de taille significative) à transmettre, utilisez multipart/form-data. Sinon, utilisez application/x-www-form-urlencoded.


Les types MIME que vous mentionnez sont les deux Content-Type des en-têtes pour les requêtes HTTP POST que les user-agents (navigateurs) doivent prendre en charge. Le but de ces deux types de requêtes est d'envoyer une liste de paires nom / valeur au serveur. Selon le type et la quantité de données transmises, l'une des méthodes sera plus efficace que l'autre. Pour comprendre pourquoi, vous devez regarder ce que chacun fait sous les couvertures.

Pour application/x-www-form-urlencoded, le corps du message HTTP envoyé au serveur est essentiellement une chaîne de requête géante - les paires nom / valeur sont séparées par l'esperluette (&), et les noms sont séparés des valeurs par le symbole égal (=). Un exemple de ceci serait:

MyVariableOne=ValueOne&MyVariableTwo=ValueTwo

Selon le spécification:

Les caractères [réservés et] non alphanumériques sont remplacés par "% HH", un signe de pourcentage et deux chiffres hexadécimaux représentant le code ASCII du caractère

Cela signifie que pour chaque octet non-alphanumérique existant dans l'une de nos valeurs, il faudra trois octets pour le représenter. Pour les gros fichiers binaires, tripler la charge utile va être très inefficace.

C'est là que multipart/form-data arrive. Avec cette méthode de transmission de paires nom / valeur, chaque paire est représentée comme une "partie" dans un message MIME (comme décrit par d'autres réponses). Les parties sont séparées par une limite de chaîne particulière (choisie spécifiquement pour que cette chaîne de limite ne se produise dans aucune des charges utiles "value"). Chaque partie a son propre ensemble d'en-têtes MIME comme Content-Type, et en particulier Content-Disposition, qui peut donner à chaque partie son "nom". La valeur de chaque paire nom / valeur est la charge utile de chaque partie du message MIME. La spécification MIME nous donne plus d'options lors de la représentation de la charge utile de valeur - nous pouvons choisir un codage plus efficace des données binaires pour économiser la bande passante (par exemple base 64 ou même binaire brut).

Pourquoi ne pas utiliser multipart/form-data tout le temps? Pour les valeurs alphanumériques courtes (comme la plupart des formulaires Web), l'ajout de tous les en-têtes MIME va largement compenser les économies réalisées grâce à un encodage binaire plus efficace.


1666
2017-11-01 21:59



LISEZ AU MOINS LE PREMIER PARA ICI!

Je sais que c'est trois ans trop tard, mais la réponse de Matt (acceptée) est incomplète et finira par vous causer des ennuis. La clé ici est que, si vous choisissez d'utiliser multipart/form-data, la limite doit ne pas apparaissent dans les données du fichier que le serveur reçoit finalement.

Ce n'est pas un problème pour application/x-www-form-urlencoded, parce qu'il n'y a pas de frontière. x-www-form-urlencoded peut également toujours gérer des données binaires, par le simple fait de transformer un octet arbitraire en trois 7BIT octets. Inefficace, mais cela fonctionne (et notez que le commentaire sur le fait de ne pas pouvoir envoyer les noms de fichiers aussi bien que les données binaires est incorrect, vous l'envoyez juste comme une autre paire clé / valeur).

Le problème avec multipart/form-data est que le séparateur de frontière ne doit pas être présent dans les données de fichier (voir RFC2388; section 5.2 inclut également une excuse plutôt boiteuse pour ne pas avoir un type MIME agrégé correct qui évite ce problème).

Donc, à première vue, multipart/form-data n'a aucune valeur tout téléchargement de fichier, binaire ou autre. Si vous ne choisissez pas correctement votre limite, alors vous volonté éventuellement un problème, que vous envoyiez du texte brut ou binaire brut - le serveur trouvera une limite au mauvais endroit, et votre fichier sera tronqué, ou le POST échouera.

La clé est de choisir un encodage et une limite tels que les caractères de limite sélectionnés ne peuvent pas apparaître dans la sortie codée. Une solution simple est d'utiliser base64 (faire ne pas utiliser un fichier binaire brut). Dans base64 3 octets arbitraires sont codés en quatre caractères de 7 bits, où le jeu de caractères de sortie est [A-Za-z0-9+/=] (c'est-à-dire alphanumériques, ou '+', '/', '='). = est un cas particulier, et peut seulement apparaître à la fin de la sortie codée, comme un seul = ou un double ==. Maintenant, choisissez votre frontière comme une chaîne ASCII de 7 bits qui ne peut pas apparaître dans base64 sortie. Beaucoup de choix que vous voyez sur le net échouent à ce test - les formulaires MDN docs, par exemple, utilisez "blob" comme une limite lors de l'envoi de données binaires - pas bon. Cependant, quelque chose comme "! Blob!" n'apparaîtra jamais dans base64 sortie.


106
2018-04-18 11:08



Je ne pense pas que HTTP est limité à POST dans multipart ou x-www-form-urlencoded. le En-tête de type de contenu est orthogonal à la méthode HTTP POST (vous pouvez remplir le type MIME qui vous convient). C'est également le cas des webapps basées sur la représentation HTML typique (par exemple, la charge utile json est devenue très populaire pour la transmission de la charge utile pour les requêtes ajax).

En ce qui concerne Restful API sur HTTP, les types de contenu les plus populaires avec lesquels j'ai été contacté sont application / xml et application / json.

application / xml:

  • data-size: XML très verbeux, mais généralement pas un problème en utilisant la compression et en pensant que le cas d'accès en écriture (par exemple POST ou PUT) est beaucoup plus rare en tant qu'accès en lecture (souvent <3% de tout le trafic ). Rarement là où les cas où je devais optimiser les performances d'écriture
  • existence de caractères non-ascii: vous pouvez utiliser utf-8 comme encodage en XML
  • existence de données binaires: aurait besoin d'utiliser l'encodage base64
  • données de nom de fichier: vous pouvez encapsuler ce champ à l'intérieur de XML

application / json

  • data-size: plus compact moins de XML, texte fixe, mais vous pouvez compresser
  • caractères non-ascii: json est utf-8
  • données binaires: base64 (voir aussi json-binary-question)
  • données de nom de fichier: encapsuler comme propre section de champ dans json

données binaires en tant que ressource propre

J'essayerais de représenter les données binaires en tant que ressource / ressource propre. Il ajoute un autre appel mais décousonne mieux les choses. Exemples d'images:

POST /images
Content-type: multipart/mixed; boundary="xxxx" 
... multipart data

201 Created
Location: http://imageserver.org/../foo.jpg  

Dans les ressources ultérieures, vous pouvez simplement mettre en ligne la ressource binaire en tant que lien:

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

82
2017-10-24 16:46



Je suis d'accord avec ce que Manuel a dit. En fait, ses commentaires se réfèrent à cette url ...

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

... quels États:

Le type de contenu   "application / x-www-form-urlencoded" est   inefficace pour envoyer de grandes   quantités de données binaires ou de texte   contenant des caractères non-ASCII. le   type de contenu "multipart / form-data"   devrait être utilisé pour soumettre des formulaires   qui contiennent des fichiers, des données non-ASCII,   et des données binaires.

Cependant, pour moi, cela se résumerait à un soutien de l'outil / cadre.

  • Quels outils et cadres avez-vous Attendez-vous à ce que vos utilisateurs API construisent leurs applications avec?
  • Ont-ils cadres ou composants qu'ils peuvent utiliser qui favorisent une méthode au cours de la autre?

Si vous avez une idée claire de vos utilisateurs et de la façon dont ils utiliseront votre API, cela vous aidera à décider. Si vous effectuez le téléchargement de fichiers pour vos utilisateurs d'API, ils s'éloigneront, et vous consacrerez beaucoup de temps à leur prise en charge.

En second lieu, il y aurait le support d'outil dont vous disposez pour écrire votre API et comment il est facile pour vous d'adapter un mécanisme de téléchargement à un autre.


26
2017-10-27 12:08



Juste un petit indice de mon côté pour le téléchargement de données d'image de toile HTML5:

Je travaille sur un projet pour une imprimerie et j'ai eu quelques problèmes en raison du téléchargement d'images sur le serveur provenant d'un HTML5 canvas élément. Je luttais pendant au moins une heure et je ne l'ai pas obtenu pour enregistrer l'image correctement sur mon serveur.

Une fois que j'ai mis le contentType option de mon appel jQuery ajax à application/x-www-form-urlencoded tout s'est bien passé et les données codées en base64 ont été correctement interprétées et sauvegardées avec succès en tant qu'image.


Peut-être que cela aide quelqu'un!


0
2017-12-10 15:07