Dans HTTP, il existe deux façons de POSTER des données: application/x-www-form-urlencoded
et multipart/form-data
. Je comprends que la plupart des navigateurs ne peuvent télécharger des fichiers que s'ils multipart/form-data
sont utilisés. Existe-t-il des conseils supplémentaires sur l'utilisation d'un des types de codage dans un contexte d'API (aucun navigateur impliqué)? 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)
Jusqu'à présent, je n'ai trouvé aucune indication formelle sur le Web concernant l'utilisation des différents types de contenu.
Réponses:
TL; DR
Sommaire; si vous avez des données binaires (non alphanumériques) (ou une charge utile de taille significative) à transmettre, utilisez
multipart/form-data
. Sinon, utilisezapplication/x-www-form-urlencoded
.Les types MIME que vous mentionnez sont les deux en-
Content-Type
têtes 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, 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 la spécification :
Cela signifie que pour chaque octet non alphanumérique qui existe 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à
multipart/form-data
qu'intervient. Avec cette méthode de transmission des 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 n'apparaisse dans aucune des charges utiles de "valeur"). Chaque partie a son propre ensemble d'en-têtes MIME commeContent-Type
, et en particulierContent-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 pour représenter la valeur de la charge utile - nous pouvons choisir un encodage 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), le surcoût de l'ajout de tous les en-têtes MIME va largement compenser les économies d'un encodage binaire plus efficace.la source
LISEZ AU MOINS LE PREMIER PARA ICI!
Je sais que c'est 3 ans trop tard, mais la réponse (acceptée) de Matt est incomplète et vous causera éventuellement des ennuis. La clé ici est que, si vous choisissez d'utiliser
multipart/form-data
, la frontière ne doit pas apparaître dans les données de fichier que le serveur reçoit finalement.Ce n'est pas un problème pour
application/x-www-form-urlencoded
, car il n'y a pas de frontière.x-www-form-urlencoded
peut également toujours gérer des données binaires, par le simple expédient de transformer un octet arbitraire en trois7BIT
octets. Inefficace, mais cela fonctionne (et notez que le commentaire sur l'impossibilité d'envoyer des noms de fichiers ainsi que des données binaires est incorrect; vous l'envoyez simplement comme une autre paire clé / valeur).Le problème avec
multipart/form-data
est que le séparateur de limites ne doit pas être présent dans les données du fichier (voir RFC 2388 ; la 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
est sans valeur que ce soit dans tout transfert de fichiers, binaire ou autre. Si vous ne choisissez pas correctement votre frontière, vous aurez éventuellement un problème, que vous envoyiez du texte brut ou du binaire brut - le serveur trouvera une frontière au mauvais endroit et votre fichier sera tronqué, ou le POST échouera.La clé est de choisir un encodage et une frontière de sorte que les caractères de frontière sélectionnés ne puissent pas apparaître dans la sortie encodée. Une solution simple consiste à utiliser
base64
(ne pas utiliser de 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 ne peut apparaître qu'à la fin de la sortie codée, en simple=
ou en double==
. Maintenant, choisissez votre frontière comme une chaîne ASCII 7 bits qui ne peut pas apparaître dans labase64
sortie. De nombreux choix que vous voyez sur le net échouent à ce test - la documentation MDN Forms, par exemple, utilisez "blob" comme limite lors de l'envoi de données binaires - pas bon. Cependant, quelque chose comme "! Blob!" n'apparaîtra jamais enbase64
sortie.la source
index === -1
.'()+-./:=
alors. Pourtant , la génération aléatoire avec sous - chaîne est toujours vérifier le chemin à parcourir et il peut être fait avec une seule ligne:while(true){r = rand(); if(data.indexOf(r) === -1){doStuff();break;}}
. La suggestion d'EML (convertir en base64 juste pour éviter de faire correspondre les sous-chaînes) est tout simplement étrange, sans oublier qu'elle s'accompagne d'une dégradation des performances inutile. Et tous les ennuis pour rien puisque l'algorithme d'une ligne est tout aussi simple et simple. Base64 n'est pas censé être (ab) utilisé de cette façon, car le corps HTTP accepte tous les octets de 8 bits .Je ne pense pas que HTTP est limité à POST en multipart ou x-www-form-urlencoded. L'en -tête Content-Type 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 basées sur une représentation HTML typique (par exemple, la charge utile json est devenue très populaire pour la transmission de la charge utile pour les demandes ajax).
En ce qui concerne l'API Restful sur HTTP, les types de contenu les plus populaires avec lesquels j'ai été en contact sont application / xml et application / json.
application / xml:
application / json
données binaires comme ressource propre
J'essaierais de représenter les données binaires comme un actif / une ressource propre. Il ajoute un autre appel mais dissocie mieux les choses. Exemples d'images:
Dans les ressources ultérieures, vous pouvez simplement intégrer la ressource binaire en tant que lien:
la source
Je suis d'accord avec beaucoup de choses que Manuel a dites. 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:
Cependant, pour moi, cela se résumerait à un support outil / framework.
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 rendez le téléchargement de fichiers difficile pour vos utilisateurs d'API, ils s'éloigneront, vous passerez beaucoup de temps à les soutenir.
En second lieu, le support d'outil que vous avez pour écrire votre API et la facilité avec laquelle il est possible d'accommoder un mécanisme de téléchargement par rapport à l'autre.
la source
Juste un petit conseil de mon côté pour télécharger des données d'image de toile HTML5:
Je travaille sur un projet d'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 . J'ai eu du mal pendant au moins une heure et je n'ai pas réussi à enregistrer correctement l'image sur mon serveur.Une fois que j'ai défini l'
contentType
option de mon appel ajQuery jQuery,application/x-www-form-urlencoded
tout s'est bien passé et les données encodées en base64 ont été interprétées correctement et enregistrées avec succès en tant qu'image.Peut-être que cela aide quelqu'un!
la source
Si vous devez utiliser Content-Type = x-www-urlencoded-form, NE PAS utiliser FormDataCollection comme paramètre: Dans asp.net Core 2+ FormDataCollection n'a pas de constructeurs par défaut requis par Formatters. Utilisez IFormCollection à la place:
la source