JSON, formulaire encodé ou multipart : envoyer la bonne requête HTTP avec cURL
Deux requêtes HTTP peuvent utiliser la même URL et la même méthode tout en produisant des résultats très différents. L’une envoie un objet JSON. Une autre transmet des champs de formulaire séparés par &. Une troisième téléverse un fichier avec un délimiteur multipart. Si le serveur attend un format et en reçoit un autre, l’application peut rejeter la requête ou interpréter les valeurs de travers sans le signaler.
Ce tutoriel compare trois formats courants de corps de requête et montre comment les construire avec cURL. Vous pouvez utiliser le générateur gratuit de commandes cURL de Web2Generators pour les corps JSON et le texte littéral, ainsi que l’encodeur et décodeur URL pour examiner les valeurs de formulaire.
Distinguer l’URL du corps de la requête
Une URL peut contenir des paramètres :
https://example.com/api/items?category=books&page=2
Ces valeurs font partie de la cible de la requête. Une requête POST peut aussi inclure un corps contenant des champs ou des données structurées. Les deux peuvent coexister, mais jouent des rôles différents. Une API peut utiliser des paramètres d’URL pour la pagination et un corps JSON pour les détails d’un nouvel élément.
L’en-tête Content-Type indique au destinataire comment interpréter le corps. L’en-tête Accept indique au serveur la représentation souhaitée pour la réponse. Ils ne sont pas interchangeables.
| Format | Content-Type habituel | Usage courant |
|---|---|---|
| JSON | application/json | Objets et tableaux d’API |
| Formulaire encodé | application/x-www-form-urlencoded | Champs simples de formulaire HTML |
| Multipart | multipart/form-data; boundary=... | Fichiers et champs de formulaire |
Le bon choix dépend du contrat de l’API, pas de l’option cURL la plus courte.
1. Envoyer un corps JSON
Une API JSON attend souvent un objet de ce type :
{
"name": "Example notebook",
"quantity": 2,
"categories": ["paper", "office"]
}
Envoyez-le avec un type de contenu explicite :
curl \
--request POST \
--url 'https://example.com/api/items' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--data-raw '{"name":"Example notebook","quantity":2,"categories":["paper","office"]}'
Ces adresses sont illustratives et ne correspondent pas nécessairement à des services existants. Remplacez-les par une API qui vous appartient ou que vous êtes autorisé à tester.
--data-raw transmet le texte littéral sans vérifier qu’il s’agit de JSON valide. Dans un shell comme Bash, entourer le JSON d’apostrophes facilite l’écriture des clés entre guillemets doubles. PowerShell et l’invite de commandes Windows utilisent d’autres règles de citation ; le générateur ne produit pas de commandes pour ces shells. Sa sortie multiligne par défaut convient aux shells POSIX comme Bash ou Zsh ; la sortie sur une seule ligne nécessite Bash ou Zsh.
Avec cURL 7.82.0 ou une version ultérieure, --json (documentation en anglais) constitue une alternative pratique :
curl --json '{"name":"Example notebook","quantity":2}' \
'https://example.com/api/items'
Cette option ajoute les en-têtes JSON et envoie les données par POST, mais ne valide pas non plus la structure JSON. Si le serveur renvoie une erreur de validation, comparez les noms des champs, leurs types et les propriétés obligatoires avant de chercher un problème de transport HTTP.
2. Envoyer des champs de formulaire encodés
Les formulaires HTML traditionnels utilisent souvent application/x-www-form-urlencoded. Le corps ressemble alors à une chaîne de paramètres d’URL :
q=C%2B%2B+tips&tag=programming&tag=beginner
Après décodage de formulaire, le terme recherché est C++ tips. Les séquences %2B préservent les signes plus littéraux ; le + non échappé représente un espace. Il y a deux champs tag. La conservation des deux valeurs côté serveur dépend de son analyseur et du contrat de l’API.
Une requête construite à la main peut ressembler à ceci :
curl \
--request POST \
--url 'https://example.com/search' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-raw 'q=C%2B%2B+tips&tag=programming&tag=beginner'
Pour construire la requête directement avec cURL, --data-urlencode peut encoder chaque valeur à votre place :
curl \
--url 'https://example.com/search' \
--data-urlencode 'q=C++ tips' \
--data-urlencode 'tag=programming' \
--data-urlencode 'tag=beginner'
Sans --get, ces options envoient un corps POST par défaut. cURL définit aussi le type de contenu habituel des formulaires pour ces options si vous ne le remplacez pas. Pour placer les paramètres dans une requête GET, ajoutez --get. Avec la syntaxe name=value, cURL encode la valeur : les noms de champs contenant des caractères spéciaux doivent donc être déjà encodés.
L’encodeur, décodeur et éditeur de paramètres URL permet d’examiner ces différences. Choisissez Valeur de formulaire (espaces en +) pour voir comment sont encodés les espaces, les signes plus littéraux, les esperluettes et les caractères non ASCII. Le billet Découvrez notre encodeur, décodeur et éditeur de paramètres URL explique aussi l’intérêt des noms répétés.
3. Téléverser un fichier avec des données multipart
Utilisez multipart/form-data lorsque le point d’accès attend un fichier téléversé dans un champ de formulaire. Certaines API attendent plutôt les octets du fichier comme corps complet : suivez leur documentation. Une requête multipart comporte des parties délimitées séparément, chacune avec ses propres en-têtes. Ce n’est ni une longue chaîne de formulaire encodé ni un document JSON dans lequel on aurait collé un nom de fichier.
Utilisez --form pour le champ fichier :
curl \
--url 'https://example.com/api/uploads' \
--form-string 'description=Test document' \
--form 'document=@./demo.txt;type=text/plain'
L’option --form-string conserve la description littérale, même si elle commence par @ ou <. Dans le champ fichier, @ indique à cURL de lire le fichier local ./demo.txt. Créez d’abord un fichier de test sans données sensibles et vérifiez son chemin. Contrairement au JSON et aux formulaires envoyés comme texte littéral, le contenu du fichier forme une partie multipart distincte.
Laissez cURL générer le corps multipart et son en-tête Content-Type. Le délimiteur indiqué dans l’en-tête doit correspondre à ceux du corps. Avec --form, cURL gère les deux ; vous n’avez pas à les construire à la main. Ajouter un en-tête multipart à un corps de texte littéral ne le transforme pas en téléversement de fichier.
Le générateur Web2Generators produit actuellement des corps littéraux avec --data-raw ; il ne propose pas de champs de fichier multipart. Préparez cette commande de téléversement dans votre terminal à partir de l’exemple ci-dessus.
Examinez les exemples cURL copiés depuis les outils de développement du navigateur avant de les partager. Ils peuvent contenir des cookies de session, des jetons d’accès ou d’autres valeurs sensibles. Retirez-les ou remplacez-les avant de coller les commandes dans un ticket ou une documentation publique.
Pourquoi le serveur renvoie 400, 415 ou 422
Une requête peut atteindre le bon point d’accès tout en échouant. Voici quelques cas courants :
| Symptôme | Cause possible | Première vérification |
|---|---|---|
400 Bad Request | Syntaxe mal formée ou requête invalide | Le JSON est-il valide ? Les séparateurs de formulaire sont-ils corrects ? |
415 Unsupported Media Type | Format du corps non pris en charge | Content-Type correspond-il au contrat de l’API ? |
422 Unprocessable Content | Syntaxe comprise, mais valeurs non conformes aux règles | Vérifiez les champs obligatoires, les types et les messages de validation. |
| Champs manquants | Le serveur a interprété un autre format | Comparez le corps brut et la configuration de l’analyseur. |
| Champ fichier vide | Nom du champ ou délimiteur multipart incorrect | Vérifiez --form, le nom du champ et le chemin du fichier. |
Les codes de statut sont des indices, pas des diagnostics universels. La documentation de l’API et le corps de sa réponse restent les meilleures sources pour ses règles de validation. Vérifiez aussi si une redirection modifie le comportement de la requête avant son arrivée au point d’accès final.
Comparer les requêtes du navigateur et du terminal
Un formulaire fonctionne dans le navigateur, mais échoue depuis le terminal ? Ouvrez son entrée dans le panneau Réseau et relevez la méthode, l’URL, Content-Type, les champs envoyés et la réponse. Le guide Web2Generators pour examiner les requêtes réseau d’un site indique où trouver ces informations dans Chrome, Firefox, Edge et Safari.
Construisez ensuite la plus petite requête cURL qui représente les mêmes données pour l’application. Le guide des commandes cURL propose d’autres exemples d’en-têtes, d’authentification, de citation et d’options de diagnostic.
Une méthode utile :
- Partez d’une requête qui fonctionne dans un environnement de test, en conservant l’authentification nécessaire avec des identifiants de test.
- Modifiez un seul élément : format, en-tête ou valeur de champ.
- Relevez le code de statut et le corps de la réponse.
- Confirmez ce que le serveur a réellement reçu, à l’aide de ses journaux si vous êtes autorisé à les consulter.
- Retirez les en-têtes superflus un par un tout en préservant l’authentification requise.
Si vous changez cinq variables à la fois, l’erreur obtenue vous apprendra peu de choses.
L’échappement HTML n’est pas l’encodage de formulaire
Les mêmes caractères peuvent apparaître dans le code HTML et dans les données de formulaire, mais les règles d’échappement répondent à des besoins différents. Dans le texte d’une source HTML, une esperluette peut s’écrire &. Dans un corps de formulaire, une esperluette littérale à l’intérieur d’une valeur s’encode en %26 ; un & brut sépare normalement les champs. L’une de ces opérations ne remplace pas l’autre.
L’encodeur et décodeur HTML et l’article sur l’échappement HTML et l’assainissement expliquent le côté HTML. Appliquez la règle correspondant au contexte réel d’utilisation des données.
Vérifier la requête avant de la partager
Avant de partager une reproduction d’appel API, vérifiez la méthode et le point d’accès, la conformité du corps au schéma documenté, la correspondance entre Content-Type et les octets envoyés, ainsi que la nécessité de Accept. Conservez les champs répétés lorsque le serveur les prend en charge. Pour les téléversements multipart, laissez cURL créer le délimiteur. Retirez les identifiants de vos rapports et n’envoyez pas de fichiers privés de production à un service de test.
Préparez votre premier POST JSON
Ouvrez le générateur gratuit de commandes cURL, choisissez POST, saisissez votre point d’accès de test et sélectionnez application/json dans Content-Type. Collez {"name":"Example notebook","quantity":2} dans Corps de la requête, puis sélectionnez Copier la commande et exécutez-la dans Bash ou Zsh. Le générateur prépare la commande localement ; il n’envoie pas la requête et ne valide pas le JSON. Comparez la réponse aux champs documentés par votre API avant d’ajouter d’autres options.