Content-Type
Utilisation
L’en-tête Content-Type indique au client (ou au serveur, dans le cas des corps de requête) le type de média du contenu transporté. Le type de média détermine la façon dont le destinataire analyse et restitue le corps du message. En l’absence de cet en-tête, les clients se rabattent sur le MIME sniffing, ce qui introduit des risques de sécurité et des comportements incohérents.
Remarque
Accept déclare ce que le client souhaite recevoir. Content-Type déclare ce qui est envoyé. Accept apparaît dans les requêtes. Content-Type apparaît à la fois dans les requêtes (lorsqu’un corps est présent) et dans les réponses. Les requêtes GET n’ont généralement pas de corps et n’ont pas besoin de Content-Type. Les requêtes POST et PUT dotées d’un corps exigent cet en-tête.
Un type de média se compose d’un type de premier niveau et d’un sous-type séparés par une barre oblique, éventuellement suivis de paramètres. L’en-tête de requête Accept fonctionne de pair avec Content-Type lors de la négociation de contenu : il permet au client d’exprimer les types de médias qu’il préfère avant que le serveur n’en sélectionne un.
Les serveurs et les intermédiaires appliquent parfois un Content-Encoding (comme gzip ou br) avant la transmission. L’en-tête Content-Type décrit toujours le type de média d’origine, avant encodage, et non le format encodé.
L’en-tête MIME-Version remonte aux origines des types MIME dans la messagerie électronique et apparaît dans certains messages HTTP, bien que HTTP n’exige pas cet en-tête pour le traitement des types de médias.
media-type
La valeur du type de média suit le format type/subtype enregistré auprès de l’IANA. Les types courants incluent text/html, application/json, image/png et application/octet-stream. Un registre complet est maintenu par l’IANA.
charset
Le paramètre charset indique l’encodage de caractères des types de médias textuels. UTF-8 est l’encodage dominant sur le Web.
Content-Type: text/html; charset=UTF-8
boundary
Le paramètre boundary est obligatoire pour les types de médias multipart/*. La chaîne de délimitation sépare chaque partie du corps multipart. La valeur de boundary ne doit apparaître dans aucune des parties du corps.
Content-Type: multipart/form-data; boundary=----FormBoundary
Exemple
Un serveur renvoie une page HTML encodée en UTF-8. Le navigateur utilise le type de média pour restituer le contenu sous forme de page web et le charset pour décoder correctement le texte.
Content-Type: text/html; charset=UTF-8
Une API renvoie une réponse JSON. Le type de média application/json indique au client d’analyser le corps comme du JSON.
Content-Type: application/json
Une réponse d’erreur d’API utilise le type de média application/problem+json pour signaler une charge utile structurée de détails de problème.
Content-Type: application/problem+json
Un CDN convertit une page HTML en Markdown à la volée lorsque le client envoie Accept: text/markdown. La réponse porte text/markdown comme type de contenu, signalant que le corps est du Markdown plutôt que du HTML.
Content-Type: text/markdown; charset=utf-8
Agents IA et Content-Type
Des fournisseurs de CDN comme Cloudflare renvoient Content-Type: text/markdown accompagné d’un en-tête x-markdown-tokens estimant le nombre de tokens du document converti. Les agents utilisent le type de contenu pour choisir le bon analyseur et l’estimation de tokens pour gérer le budget de leur fenêtre de contexte.
Un envoi de fichier utilise multipart/form-data avec une chaîne de délimitation séparant les champs de formulaire et les données du fichier dans le corps de la requête.
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW
Un serveur livre un fichier binaire en téléchargement. Le type application/octet-stream signale des données binaires brutes, souvent associé à un en-tête Content-Disposition réglé sur attachment.
Content-Type: application/octet-stream
Une réponse multipart/byteranges livre plusieurs plages d’octets issues d’une même ressource. Chaque partie dispose de ses propres en-têtes Content-Type et Content-Range.
Content-Type: multipart/byteranges; boundary=THIS_STRING_SEPARATES
Dépannage
Les échecs de rendu et les erreurs d’analyse remontent souvent à un en-tête Content-Type manquant ou incorrect.
Un paramètre charset manquant provoque du texte illisible. Les navigateurs se rabattent sur un encodage par défaut (souvent ISO-8859-1) lorsqu’aucun charset n’est déclaré. Les caractères non-ASCII apparaissent sous forme de mojibake. Ajoutez explicitement le paramètre charset : Content-Type: text/html; charset=UTF-8. Dans nginx :
charset utf-8;
Dans Apache :
AddDefaultCharset UTF-8
Le navigateur applique le MIME sniffing malgré un Content-Type correct. Les navigateurs ignorent parfois le type déclaré et inspectent le contenu du corps pour déterminer le type. Ce comportement ouvre des vecteurs d’attaque XSS lorsque du contenu téléversé par les utilisateurs est servi comme du HTML. Ajoutez l’en-tête X-Content-Type-Options réglé sur nosniff pour bloquer le MIME sniffing :
X-Content-Type-Options: nosniff
L’API renvoie text/html au lieu de application/json. Les clients qui analysent du JSON provenant d’une API reçoivent des pages d’erreur HTML ou des réponses par défaut du framework. Cela se produit lorsqu’un gestionnaire d’erreurs ou un proxy inverse intercepte la réponse et remplace le corps sans mettre à jour le Content-Type. Vérifiez toute la chaîne de réponse : serveur d’origine, framework applicatif, proxy inverse et CDN. Dans Express.js, l’appel à res.json() définit automatiquement le bon en-tête. Dans Django, renvoyez JsonResponse plutôt que HttpResponse.
Une discordance de boundary multipart casse les envois de fichiers. La chaîne de délimitation déclarée dans l’en-tête Content-Type doit correspondre au délimiteur utilisé dans le corps de la requête. Une discordance empêche le serveur d’analyser le corps multipart. Inspectez la requête brute dans l’onglet Network des DevTools, sous les sections Headers et Payload. Évitez de définir le boundary manuellement lorsque vous utilisez fetch() ou XMLHttpRequest avec des objets FormData. Le navigateur génère automatiquement le bon boundary lorsque l’en-tête Content-Type est omis de la requête.
Le Content-Type par défaut du framework écrase un réglage explicite. Certains frameworks définissent Content-Type après l’exécution du code applicatif. Un middleware dans Express.js, Django ou Spring Boot peut réinitialiser l’en-tête. Vérifiez l’ordre d’exécution des middlewares. Dans Express.js, assurez-vous que res.type() ou res.set(‘Content-Type’, …) est appelé après tous les middlewares qui modifient les en-têtes.
Diagnostiquer les problèmes de Content-Type avec les DevTools. Ouvrez l’onglet Network des DevTools du navigateur, sélectionnez la requête et examinez la section Response Headers pour y lire la valeur de Content-Type. Comparez le type déclaré avec le contenu réel du corps affiché dans l’onglet Response ou Preview. Utilisez curl -I https://example.re/api/data pour inspecter les en-têtes en ligne de commande, sans interférence du navigateur.