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

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

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

Jusqu'à présent, je n'ai trouvé aucune indication formelle sur le web concernant l'utilisation des différents types de contenu.

Solution

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 en-têtes Content-Type des requêtes HTTP POST que les agents utilisateurs (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, il faut examiner ce que chacune d'entre elles fait sous le manteau.

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 (=). Voici un exemple : &nbsp ;

MaVariableOne=ValeurOne&MaVariableTwo=ValeurTwo

Selon la [spécification] (http://www.w3.org/TR/html401/interact/forms.html) :

[Réservé et] les caractères non alphanumériques sont remplacés par `%HH&#39 ;, 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 sera très inefficace.

C'est là qu'intervient multipart/form-data. Avec cette méthode de transmission de paires nom/valeur, chaque paire est représentée comme une "partie&quot ; dans un message MIME (comme décrit dans d'autres réponses). Les parties sont séparées par une chaîne de caractères particulière (choisie spécifiquement pour que cette chaîne de caractères ne se retrouve dans aucune des charges utiles de type "value"). Chaque partie a son propre ensemble d'en-têtes MIME comme Content-Type, et particulièrement Content-Disposition, qui peut donner à chaque partie son "nom.&quot ; La partie 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 pour représenter les données utiles : 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 dépasser les économies réalisées grâce à un encodage binaire plus efficace.

Commentaires (16)

Je ne pense pas que HTTP soit limité au POST en multipart ou x-www-form-urlencoded. Le [Content-Type Header][1] est orthogonal à la méthode HTTP POST (vous pouvez remplir le type MIME qui vous convient). C'est également le cas pour les applications web typiques basées sur la représentation HTML (par exemple, la charge utile json est devenue très populaire pour transmettre la charge utile des requêtes ajax).

En ce qui concerne l'API reposante sur HTTP, les types de contenu les plus populaires que j'ai rencontrés sont application/xml et application/json.

application/xml :

  • data-size : XML très verbeux, mais ce n'est généralement pas un problème si l'on utilise la compression et si l'on pense que l'accès en écriture (par exemple via POST ou PUT) est beaucoup plus rare que l'accès en lecture (dans de nombreux cas, il représente 3 % du trafic total). Il y a rarement eu des cas où j'ai dû optimiser les performances en écriture
  • existence de caractères non ascii : vous pouvez utiliser utf-8 comme encodage dans XML
  • existence de données binaires : il faut utiliser l'encodage base64
  • données de nom de fichier : vous pouvez les encapsuler dans un champ en XML

application/json

  • taille des données : plus compact que le XML, toujours du texte, mais vous pouvez le compresser
  • caractères non ascii : json est utf-8
  • données binaires : base64 (voir aussi [json-binary-question][2])
  • données de nom de fichier : encapsulées en tant que section de champ propre dans json

données binaires en tant que ressource propre

Je voudrais essayer de représenter les données binaires comme un actif/une ressource propre. Cela ajoute un autre appel mais découple mieux les choses. Exemples d'images :

POST /images
Content-type : multipart/mixed ; boundary="xxxx" ;
... données multipart

201 Créé Emplacement : http://imageserver.org/../foo.jpg

Dans les ressources ultérieures, vous pourriez simplement mettre en ligne la ressource binaire comme lien :

Commentaires (3)

Je suis d'accord avec beaucoup de ce que Manuel a dit. En fait, ses commentaires font référence à cette url...

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

... qui déclare :

Le type de contenu "application/x-www-form-urlencoded&quot ; est inefficace pour l'envoi de grandes de grandes quantités de données binaires ou de texte contenant des caractères non ASCII. L'adresse type de contenu "multipart/form-data&quot ; doit être utilisé pour l'envoi de formulaires qui contiennent des fichiers, des données non ASCII et des données binaires.

Toutefois, pour moi, cela se résume à la prise en charge d'un outil ou d'un cadre.

  • Quels outils et cadres de travail que les utilisateurs de votre API construisent leurs applications ?
  • Disposent-ils de frameworks ou composants qu'ils peuvent utiliser qui favorisent une méthode plutôt que l'autre ?

Si vous avez une idée précise de vos utilisateurs et de la manière dont ils utiliseront votre API, cela vous aidera à prendre une décision. Si vous rendez le téléchargement de fichiers difficile pour les utilisateurs de votre API, ils s&#8217en éloigneront, ou vous passerez beaucoup de temps à les soutenir.

En second lieu, il faut tenir compte de l'aide que VOUS apportez à l'écriture de votre API et de la facilité avec laquelle vous pouvez adapter un mécanisme de téléchargement à un autre.

Commentaires (2)