Comment les paramètres sont-ils envoyés dans une requête HTTP POST?

1476

Dans une requête HTTP GET , les paramètres sont envoyés sous forme de chaîne de requête :

http://example.com/page ? parameter = value & also = another

Dans une demande HTTP POST , les paramètres ne sont pas envoyés avec l'URI.

Où sont les valeurs? Dans l'en-tête de demande? Dans l'organe de requête? À quoi cela ressemble-t-il?

Camilo Martin
la source

Réponses:

1255

Les valeurs sont envoyées dans le corps de la demande, au format spécifié par le type de contenu.

Généralement, le type de contenu est application/x-www-form-urlencoded, donc le corps de la demande utilise le même format que la chaîne de requête:

parameter=value&also=another

Lorsque vous utilisez un téléchargement de fichier dans le formulaire, vous utilisez multipart/form-dataplutôt l' encodage, qui a un format différent. C'est plus compliqué, mais vous n'avez généralement pas besoin de vous soucier de son apparence, donc je ne montrerai pas d'exemple, mais il peut être bon de savoir qu'il existe.

Guffa
la source
25
J'avais oublié que les téléchargements de fichiers étaient différents (+ 1 / accepté). Votre réponse est suffisante, alors qu'elle serait très agréable si elle avait plus d'informations sur multipart/form-data. Pour ceux qui sont intéressés, voici une question à ce sujet .
Camilo Martin
73
REMARQUE : le corps est séparé de l'en-tête par une seule ligne vierge .
Gab 是 好人
2
Vous avez expliqué ce que nous plaçons dans HTTPBody, mais que plaçons-nous / écrivons-nous dans HTTPHeader? A quoi cela sert-il?
Honey
4
@Honey: l'en-tête HTTP d'un article ressemble à un pour un get, mais avec le verbe POST au lieu de GET, et une valeur de type de contenu (et une valeur de longueur de contenu facultative) car la demande a du contenu (corps). Chaque type de demande a un en-tête, certains types ont également un corps.
Guffa
4
@KennethWorden Non, aucune des méthodes n'enverra correctement JSON. vous pouvez cependant télécharger un fichier json sous une forme codée avec multipart/form-dataou si vous êtes en charge de la construction de la demande, changer le type de contenu application/jsonet coller le texte json directement dans le corps http
Cholthi Paul Ttiopic
428

Le contenu est placé après les en-têtes HTTP. Le format d'un HTTP POST est d'avoir les en-têtes HTTP, suivis d'une ligne vierge, suivis du corps de la requête. Les variables POST sont stockées sous forme de paires clé-valeur dans le corps.

Vous pouvez le voir dans le contenu brut d'une publication HTTP, illustré ci-dessous:

POST /path/script.cgi HTTP/1.0
From: [email protected]
User-Agent: HTTPTool/1.0
Content-Type: application/x-www-form-urlencoded
Content-Length: 32

home=Cosby&favorite+flavor=flies

Vous pouvez le voir en utilisant un outil comme Fiddler , que vous pouvez utiliser pour regarder les charges utiles brutes de demande et de réponse HTTP envoyées sur le câble.

Joe Alfano
la source
39
Seulement si le type de contenu est application/x-www-form-urlencoded, ce qui n'est pas toujours le cas.
Guffa
@ Camilo Martin .... [+1] pour une excellente question & @ Joe Alfano .... [+1] pour une excellente réponse ....... j'ai maintenant une idée claire de la demande POST .... mais si une image s'accompagne d'une paire clé, valeur d'informations sur les données ..... À quoi ressemble la structure de POST?
Devrath
9
@ Joe, maintenant pourquoi auriez-vous un en- Fromtête là-bas?
Pacerier
@Joe, j'aime l'inclusion aléatoire de l'en- Fromtête. OMI, il est là-haut avec le code d'état HTTP 418.
Tom Howard
comment ajouter une authentification utilisateur et mot de passe?
m4l490n
376

Réponse courte: dans les requêtes POST, les valeurs sont envoyées dans le "corps" de la requête. Avec les formulaires Web, ils sont très probablement envoyés avec un type de support application/x-www-form-urlencodedou multipart/form-data. Les langages de programmation ou des cadres qui ont été conçus pour gérer les requêtes web ne sont généralement « The Right Thing ™ » avec ces demandes et vous fournir un accès facile aux valeurs facilement décodés (comme $_REQUESTou $_POSTen PHP, ou cgi.FieldStorage(), flask.request.formen Python).


Maintenant, nous allons nous éloigner un peu, ce qui peut aider à comprendre la différence;)

La différence entre GETet les POSTdemandes sont largement sémantiques. Ils sont également «utilisés» différemment, ce qui explique la différence dans la façon dont les valeurs sont transmises.

GET ( section RFC pertinente )

Lors de l'exécution d'une GETdemande, vous en demandez une au serveur ou un ensemble d'entités. Pour permettre au client de filtrer le résultat, il peut utiliser la "chaîne de requête" de l'URL. La chaîne de requête est la partie après le ?. Cela fait partie de la syntaxe URI .

Ainsi, du point de vue de votre code d'application (la partie qui reçoit la demande), vous devrez inspecter la partie de requête URI pour accéder à ces valeurs.

Notez que les clés et les valeurs font partie de l'URI. Les navigateurs peuvent imposer une limite à la longueur de l'URI. La norme HTTP indique qu'il n'y a pas de limite. Mais au moment où nous écrivons ces lignes, la plupart des navigateurs ne limitent les URIs (je n'ai pas de valeurs spécifiques). GETles demandes ne doivent jamais être utilisées pour soumettre de nouvelles informations au serveur. Surtout pas des documents plus volumineux. C'est là que vous devez utiliser POSTou PUT.

POST ( section RFC pertinente )

Lors de l'exécution d'une POSTdemande, le client soumet en fait un nouveau document à l'hôte distant. Ainsi, une chaîne de requête n'a pas (sémantiquement) de sens. C'est pourquoi vous n'y avez pas accès dans votre code d'application.

POSTest un peu plus complexe (et beaucoup plus flexible):

Lors de la réception d'une demande POST, vous devez toujours vous attendre à une "charge utile" ou, en termes HTTP: un corps de message . Le corps du message en lui-même est assez inutile, car il n'y a pas de format standard (pour autant que je sache. Peut-être application / octet-stream?). Le format du corps est défini par l'en- Content-Typetête. Lorsque vous utilisez un FORMélément HTML avec method="POST", c'est généralement le cas application/x-www-form-urlencoded. Un autre type très courant est le multipart / form-data si vous utilisez des téléchargements de fichiers. Mais cela pourrait être n'importe quoi , allant de text/plain, au-dessus application/jsonou même une coutume application/octet-stream.

Dans tous les cas, si une POSTdemande est faite avec un Content-Typequi ne peut pas être traité par l'application, elle doit renvoyer un 415code d'état .

La plupart des langages de programmation (et / ou cadres Web) offrent un moyen de dé / coder le corps du message de / vers les types les plus courants (comme application/x-www-form-urlencoded, multipart/form-dataou application/json). C'est donc simple. Les types personnalisés nécessitent potentiellement un peu plus de travail.

En utilisant un document codé de formulaire HTML standard comme exemple, l'application doit effectuer les étapes suivantes:

  1. Lire le Content-Typeterrain
  2. Si la valeur n'est pas l'un des types de supports pris en charge, retournez une réponse avec un 415code d'état
  3. sinon, décodez les valeurs du corps du message.

Encore une fois, des langages comme PHP ou des frameworks Web pour d'autres langages populaires s'en occuperont probablement pour vous. L'exception à cela est l' 415erreur. Aucun cadre ne peut prédire les types de contenu que votre application choisit de prendre en charge et / ou de ne pas prendre en charge. C'est à toi de décider.

PUT ( section RFC pertinente )

Une PUTdemande est à peu près traitée de la même manière qu'une POSTdemande. La grande différence est qu'une POSTdemande est censée laisser le serveur décider comment (et le cas échéant) créer une nouvelle ressource. Historiquement (à partir de la RFC2616 désormais obsolète, il s'agissait de créer une nouvelle ressource en tant que "subordonné" (enfant) de l'URI où la demande a été envoyée).

Une PUTdemande en revanche est censée «déposer» une ressource exactement à cet URI, et avec exactement ce contenu. Ni plus ni moins. L'idée est que le client est responsable de créer la ressource complète avant de la "METTRE". Le serveur doit l'accepter tel quel sur l'URL donnée.

Par conséquent, une POSTdemande n'est généralement pas utilisée pour remplacer une ressource existante. Une PUTdemande peut à la fois créer et remplacer.

Side-Note

Il existe également des " paramètres de chemin " qui peuvent être utilisés pour envoyer des données supplémentaires à la télécommande, mais ils sont si rares que je n'entrerai pas dans trop de détails ici. Mais, pour référence, voici un extrait du RFC:

Mis à part les segments de points dans les chemins hiérarchiques, un segment de chemin est considéré comme opaque par la syntaxe générique. Les applications produisant des URI utilisent souvent les caractères réservés autorisés dans un segment pour délimiter des sous-composants spécifiques au schéma ou au gestionnaire de déréférence. Par exemple, les points réservés point-virgule (";") et égal ("=") sont souvent utilisés pour délimiter les paramètres et les valeurs de paramètre applicables à ce segment. Le caractère réservé virgule (",") est souvent utilisé à des fins similaires. Par exemple, un producteur d'URI peut utiliser un segment tel que "nom; v = 1.1" pour indiquer une référence à la version 1.1 de "nom", tandis qu'un autre peut utiliser un segment tel que "nom, 1.1" pour l'indiquer. Les types de paramètres peuvent être définis par une sémantique spécifique au schéma,

exhuma
la source
1
Je suis peut-être allé sur une légère tangente en effet. J'ai ajouté un "tl; dr" en haut de la réponse qui devrait le rendre plus clair.
exhuma
Je viens également de le modifier pour référencer le RFC7231 au lieu du RFC2616 (qui est obsolète depuis un certain temps). La principale différence pour cette réponse en dehors des liens mis à jour, se trouve dans la section "PUT".
exhuma
Je pensais que PUT était géré différemment de POST car il est censé être idempotent? stackoverflow.com/questions/611906/…
rogerdpack
1
@rogerdpack Vous ne vous trompez pas. Si vous lisez le deuxième paragraphe de la PUTsection, vous verrez qu'il est idempotent. POSTen revanche ne peut pas - par définition - être. POSTcréera toujours une nouvelle ressource. PUTsera, s'il existe une ressource identique, la remplacer. Donc, si vous appelez POST10 fois, vous créerez 10 ressources. Si vous appelez PUT10 fois, il n'en créera (peut-être) qu'un. Est-ce que ça répond à votre question?
exhuma
60

Vous ne pouvez pas le saisir directement dans la barre d'URL du navigateur.

Vous pouvez voir comment les données POST sont envoyées sur Internet avec des en-têtes HTTP en direct, par exemple. Le résultat sera quelque chose comme ça

http://127.0.0.1/pass.php
POST /pass.php HTTP/1.1

Host: 127.0.0.1
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:18.0) Gecko/20100101 Firefox/18.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
DNT: 1
Referer: http://127.0.0.1/pass.php
Cookie: passx=87e8af376bc9d9bfec2c7c0193e6af70; PHPSESSID=l9hk7mfh0ppqecg8gialak6gt5
Connection: keep-alive
Content-Type: application/x-www-form-urlencoded
Content-Length: 30
username=zurfyx&pass=password

Où il est dit

Content-Length: 30
    username=zurfyx&pass=password

seront les valeurs de publication.

zurfyx
la source
2
Clarification: est Content-Lengthcensé être 29ici? C'est la longueur réelle de la chaîne username=zurfyx&pass=password.
Hippo
@Hippo était un caractère de nouvelle ligne censé être là?
vikingsteve
@vikingsteve Je vois ce que tu veux dire. Donc je suppose que le contenu a toujours une nouvelle ligne à la fin, alors.
Hippo
2
L'en-tête est séparé du corps avec une nouvelle ligne supplémentaire
Mára Toner
24

Le type de support par défaut dans une demande POST est application/x-www-form-urlencoded. Il s'agit d'un format de codage des paires clé-valeur. Les clés peuvent être dupliquées. Chaque paire clé-valeur est séparée par un &caractère, et chaque clé est séparée de sa valeur par un =caractère.

Par exemple:

Name: John Smith
Grade: 19

Est codé comme:

Name=John+Smith&Grade=19

Ceci est placé dans le corps de la demande après les en-têtes HTTP.

Nejat
la source
1
Vous avez expliqué ce que nous plaçons dans HTTPBody, mais que plaçons-nous / écrivons-nous dans HTTPHeader?
Honey
Vous avez mentionné que la clé peut être en double, alors quel est le résultat d'un tel duplicata? La dernière remplacera-t-elle automatiquement la ou les valeurs précédentes? Merci.
Jinghui Niu
@JinghuiNiu si la clé est en double, elle doit être analysée en tant que tableau. C'est très tard mais cela pourrait aider quelqu'un d'autre.
Hanash Yaslem
18

Les valeurs de formulaire dans HTTP POST sont envoyées dans le corps de la demande, au même format que la chaîne de requête.

Pour plus d'informations, voir la spécification .

SLaks
la source
5
"Même format" est un peu ambigu. Commencent-ils par un ?exemple?
Camilo Martin
7
@PeterWooster Oui, mais ne fournit pas d'exemple. À cet égard, c'est comme une réponse qui dit "regardez, il y a une réponse à votre question dans le blog de l'application (lien) ".
Camilo Martin
36
@PeterWooster Ce n'est pas nécessaire, mais c'est très bien lorsque vous oubliez quelque chose, recherchez-le sur Google, accédez au premier lien qui est SO, et il y a un exemple clair et concis qui vous dit ce dont vous avez besoin au lieu de vous envoyer à mâcher sur le des spécifications trop détaillées qui, même si elles sont complètes, peuvent ne pas convenir aux rafraîchisseurs. Pensez-y: la plupart des QA sur ce site pourraient se résumer à "aller lire la spécification / manuel / API / etc (lien) ". Serait-ce utile? Pas plus que Google.
Camilo Martin
2
Seulement si le type de contenu est application/x-www-form-urlencoded, ce qui n'est pas toujours le cas.
Guffa
3
Le format de la chaîne de requête GET est différent de celui de l'application / x-www-form-urlencoded. Par exemple, les espaces blancs sont codés différemment (% 20 vs +). La réponse est trompeuse à cet égard.
UnclickableCharacter
18

Certains services Web nécessitent que vous placiez les données de demande et les métadonnées séparément. Par exemple, une fonction distante peut s'attendre à ce que la chaîne de métadonnées signée soit incluse dans un URI, tandis que les données sont publiées dans un corps HTTP.

La requête POST peut ressembler sémantiquement à ceci:

POST /?AuthId=YOURKEY&Action=WebServiceAction&Signature=rcLXfkPldrYm04 HTTP/1.1
Content-Type: text/tab-separated-values; charset=iso-8859-1
Content-Length: []
Host: webservices.domain.com
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Encoding: identity
User-Agent: Mozilla/3.0 (compatible; Indy Library)

name    id
John    G12N
Sarah   J87M
Bob     N33Y

Cette approche combine logiquement QueryString et Body-Post en utilisant un seul Content-Typequi est une "instruction d'analyse" pour un serveur Web.

Remarque: HTTP / 1.1 est entouré de #32(espace) à gauche et de #10(Saut de ligne) à droite.

Interface inconnue
la source
La différence entre /user/johnet /?user=johnest simplement sémantique (HTTP ne donne pas vraiment de traitement spécial aux chaînes de requête), donc je considère cela comme raisonnablement attendu. Mais que voulez-vous dire par «enveloppé par un espace à gauche»? Il n'y a pas d'espaces avant la méthode HTTP. Vous voulez dire la ligne vierge pour le corps du message?
Camilo Martin
Il y a un espace (ASCII # 32) entre ...Ym04et HTTP/1.1dans le code ci-dessus. Un QueryString réside donc simplement entre le verbe et la version du protocole.
Interface inconnue du
1
Votre note donne l'impression que c'est quelque chose d'inattendu et de version spécifique. Franchement, il semble évident qu'il y a un espace là-bas. Et le saut de ligne s'applique également aux autres lignes, comme toutes les choses sous Unix.
Camilo Martin
1
Je viens de souligner ce que je ne pouvais pas marquer dans le code. Cela peut sembler évident, mais parfois ce n'est pas le cas.
Interface inconnue
Il est vrai que nous pourrions passer les paramètres de requête dans le cadre de l'URL en séparant l'URI et les paramètres avec un ?comme nous le faisons avec les GETdemandes.
asgs
8

Tout d'abord, faisons la différence entre GETetPOST

Get: il s'agit de la HTTPdemande par défaut adressée au serveur et utilisée pour récupérer les données du serveur et la chaîne de requête qui suit ?dans a URIest utilisée pour récupérer une ressource unique.

c'est le format

GET /someweb.asp?data=value HTTP/1.0

voici data=valuela valeur de la chaîne de requête passée.

POST: Il est utilisé pour envoyer des données au serveur en toute sécurité, donc tout ce qui est nécessaire, c'est le format d'une POSTdemande

POST /somweb.aspHTTP/1.0
Host: localhost
Content-Type: application/x-www-form-urlencoded //you can put any format here
Content-Length: 11 //it depends
Name= somename

Pourquoi POST sur GET?

Dans GETla valeur envoyée aux serveurs sont généralement ajoutés à l'URL de base dans la chaîne de requête, il y a maintenant 2 conséquences de cela

  • Les GETdemandes sont enregistrées dans l'historique du navigateur avec les paramètres. Vos mots de passe restent donc non chiffrés dans l'historique du navigateur. C'était un vrai problème pour Facebook à l'époque.
  • Habituellement, les serveurs ont une limite de durée URI. Si vous avez envoyé trop de paramètres, vous pourriez recevoir414 Error - URI too long

En cas de demande de publication, vos données des champs sont ajoutées au corps à la place. La longueur des paramètres de demande est calculée et ajoutée à l'en-tête pour la longueur du contenu et aucune donnée importante n'est directement ajoutée à l'URL.

Vous pouvez utiliser la section réseau des outils pour les développeurs Google pour afficher des informations de base sur la façon dont les demandes sont envoyées aux serveurs.

et vous pouvez toujours ajouter plus de valeurs dans votre Request Headerscomme Cache-Control, Origin, Accept.

Zeeshan Adil
la source
4
Les hypothèses sur la sécurité ne sont vraies que dans le contexte d'une HTTPSconnexion, non HTTP. HTTPScrypte à la fois le URL(y compris les paramètres de requête) et le Request Body, quand ne HTTPcrypte / protège ni l'un ni l'autre. Le problème décrit provient du fait que de nombreux navigateurs stockent le URIs(y compris URLs) dans leurs bases de données d'historique (généralement non cryptées). Donc, n'utilisez que le Request Body+ HTTPSpour tout ce qui est sensible.
Petru Zaharia
@PetruZaharia Je suis d'accord avec votre explication. Vous pouvez également suggérer cela comme modification et je serai heureux d'accepter! :)
Zeeshan Adil