HTTP GET with request body

je développe un nouveau service Web RESTful pour notre application.

Lorsqu'ils font une recherche sur certaines entités, les clients peuvent demander le contenu de l'entité. S'ils veulent ajouter des paramètres (par exemple trier une liste), ils peuvent ajouter ces paramètres dans la chaîne de requête.

alternativement je veux que les gens puissent spécifier ces paramètres dans le corps de la requête. HTTP / 1.1 ne semble pas l'interdire explicitement. Cela leur permettra de spécifier plus d'informations, ce qui pourrait faciliter la spécification de requêtes XML complexes.

mes questions:

  • Est-ce une bonne idée?
  • est-ce que les clients HTTP auront des problèmes avec l'utilisation des corps de requêtes dans une requête GET?

http://tools.ietf.org/html/rfc2616

1479
demandé sur K48 2009-06-11 00:47:24

17 réponses

commentaire de Roy Fielding sur l'inclusion d'un corps avec une demande GET .

Oui. En d'autres termes, tout message de requête HTTP peut contenir un corps de message, et doit donc analyser les messages avec cela à l'esprit. La sémantique du serveur pour GET, cependant, est restreinte de telle sorte qu'un corps, le cas échéant, n'a pas de signification sémantique à la demande. Exigence sur l'analyse sont séparés des exigences sur la sémantique de la méthode.

Donc, oui, vous pouvez envoyer un corps avec elle, et non, il n'est jamais utile faire.

Cela fait partie de la conception en couches de HTTP / 1.1 qui deviendra clair encore une fois que la spécification est partitionné (travaux en cours).

....Roy

Oui, vous pouvez envoyer un corps de requête avec GET mais cela ne devrait pas avoir de sens. Si vous lui donnez un sens en l'analysant sur le serveur et changer votre réponse en fonction de son contenu , alors vous ignorez cette recommandation dans Le HTTP/1.1 spec, section 4.3 :

[...] si la méthode de la requête ne comprend pas la sémantique définie pour une entité-corps, puis le message-corps DEVRAIT être ignoré lors de la manipulation de la demande.

et la description de la méthode GET dans le HTTP / 1.1 spec, section 9.3 :

la méthode GET signifie extraire n'importe quelle information ([...]) est identifiée par L'URI de la demande.

qui indique que le corps de la requête ne fait pas partie de l'identification de la ressource dans une requête GET, seulement L'URI de la requête.

1252
répondu Paul Morgan 2016-04-18 18:18:29

alors que vous pouvez le faire, dans la mesure où il n'est pas explicitement exclu par la spécification HTTP, je suggérerais de l'éviter simplement parce que les gens ne s'attendent pas à ce que les choses fonctionnent de cette façon. Il y a de nombreuses phases dans une chaîne de requêtes HTTP et bien qu'elles soient "pour la plupart" conformes aux spécifications HTTP, la seule chose que vous êtes assuré est qu'elles se comporteront comme traditionnellement utilisées par les navigateurs web. (Je pense à des choses comme les procurations transparentes, les accélérateurs, les boîtes à outils A / V, etc.)

C'est l'esprit derrière le principe de Robustesse En Gros" être libéral dans ce que vous acceptez, et conservateur dans ce que vous envoyez", vous ne voulez pas repousser les limites d'une spécification sans bonne raison.

cependant, si vous avez une bonne raison, allez-y.

240
répondu caskey 2009-06-10 20:53:43

vous allez probablement rencontrer des problèmes si vous essayez de profiter de la mise en cache. Les mandataires ne vont pas regarder dans le corps GET pour voir si les paramètres ont un impact sur la réponse.

120
répondu Darrel Miller 2009-06-10 21:10:50

Ni restclient ni RESTE " console soutenir cela, mais curl n'.

la spécification HTTP dit dans la section 4.3

un corps de message ne doit pas être inclus dans une requête si la spécification de la méthode de requête (section 5.1.1) ne permet pas d'envoyer un corps-entité dans les requêtes.

Section 5.1.1 nous redirige vers la section 9.x pour les différentes méthodes. Aucun d'entre eux interdisent explicitement l'inclusion d'un corps de message. Cependant...

à la Section 5.2 dit

la ressource exacte identifiée par une requête Internet est déterminée en examinant à la fois l'URI de la requête et le champ D'en-tête de L'hôte.

et Section 9.3 dit

la méthode GET signifie rechercher toute information (sous la forme d'une entité) identifiée par L'URI-Request.

qui, ensemble, suggèrent que lors du traitement d'une requête GET, un serveur n'est pas requis pour examiner quoi que ce soit d'autre que le champ D'en-tête Request-URI et Host.

en résumé, les spécifications HTTP ne vous empêchent pas D'envoyer un corps de messages avec GET mais il y a suffisamment ambiguïté que cela ne me surprendrait pas si elle n'était pas supportée par tous les serveurs.

62
répondu Dave Durbin 2013-03-27 10:41:38

Elasticsearch accepte les requêtes GET avec un corps. Il semble même que c'est la voie préférée: http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/common-options.html#_request_body_in_query_string

certaines bibliothèques clientes (comme le pilote Ruby) peuvent enregistrer la commande cry en mode de développement et utilisent cette syntaxe de manière extensive.

37
répondu jlecour 2013-12-03 11:15:20

ce que vous essayez de réaliser est fait depuis longtemps avec une méthode beaucoup plus courante, et qui ne repose pas sur l'utilisation d'une charge utile avec GET.

vous pouvez simplement construire votre mediatype de recherche spécifique, ou si vous voulez être plus reposant, utilisez quelque chose comme OpenSearch, et postez la demande à L'URI que le serveur instruit, say /search. Le serveur peut alors générer le résultat de la recherche ou construire l'URI final et rediriger en utilisant un 303.

Cela a l'avantage de suivre la méthode PRG traditionnelle, aide les intermédiaires de cache cache les résultats, etc.

cela dit, Les URI sont encodés de toute façon pour tout ce qui n'est pas ASCII, et il en est de même pour application/x-www-form-urlencoded et multipart/form-data. Je recommande d'utiliser ceci plutôt que de créer encore un autre format JSON personnalisé si votre intention est de supporter des scénarios Reposful.

25
répondu SerialSeb 2017-04-23 08:44:41

quel serveur l'ignorera? - fijiaaron Aug 30 ' 12 à 21: 27

Google par exemple, fait pire que de l'ignorer, il va le considérer comme une erreur !

essayez-le vous-même avec un simple netcat:

$ netcat www.google.com 80
GET / HTTP/1.1
Host: www.google.com
Content-length: 6

1234

(le contenu de 1234 est suivi de CR-LF, soit un total de 6 octets)

et vous obtiendrez:

HTTP/1.1 400 Bad Request
Server: GFE/2.0
(....)
Error 400 (Bad Request)
400. That’s an error.
Your client has issued a malformed or illegal request. That’s all we know.

vous ne recevez également 400 Mauvaise demande de Bing, Apple, etc... qui sont servis par AkamaiGhost.

donc je ne conseillerais pas d'utiliser les requêtes GET avec une entité corporelle.

23
répondu user941239 2013-06-29 21:26:20

vous pouvez soit envoyer un GET avec un corps ou envoyer un POST et renoncer à la religiosité RESTish (ce n'est pas si mal, il y a 5 ans il n'y avait qu'un seul membre de cette foi-Ses commentaires sont liés ci-dessus).

ce ne sont pas non plus de bonnes décisions, mais envoyer un GET body peut éviter des problèmes pour certains clients -- et certains serveurs.

Faire un POST pourrait avoir des obstacles avec certains RESTish cadres.

Julian Reschke suggéré ci-dessus à l'aide d'un en-tête HTTP non standard comme "SEARCH" qui pourrait être une solution élégante, sauf qu'elle est encore moins susceptible d'être prise en charge.

il pourrait être plus productif d'énumérer les clients qui peuvent ou ne peuvent pas faire chacun des énoncés ci-dessus.

les Clients qui ne peuvent pas envoyer un avec le corps (que je connais):

  • XmlHTTPRequest Fiddler

Clients qui peuvent envoyer un GET with body:

  • la plupart des navigateurs

serveurs et bibliothèques qui peuvent récupérer un corps à partir de GET:

  • Apache
  • PHP

serveurs (et mandataires) qui dépouillent un corps de GET:

  • ?
22
répondu fijiaaron 2012-08-30 21:48:49

à Partir de la RFC 2616, la section 4.3 , "Corps du Message":

un serveur doit lire et transmettre un corps de message sur n'importe quelle demande; si le la méthode de demande ne comprend pas la sémantique définie pour une entité-corps, ensuite, le corps du message doit être ignoré lors du traitement de la requête.

C'est-à-dire que les serveurs doivent toujours lire tout corps de requête fourni par le réseau (vérifier la longueur du contenu ou lire un chunked corps, etc). En outre, les mandataires doivent transmettre tout organisme de demande qu'ils reçoivent. Ensuite, si le RFC définit la sémantique du corps pour la méthode donnée, le serveur peut effectivement utiliser le corps de la requête pour générer une réponse. Cependant, si le RFC ne définit pas la sémantique du corps, le serveur doit l'ignorer.

Ce qui est en ligne avec la citation de la mise en service ci-dessus.

Section 9.3 , " GET", décrit la sémantique de la méthode GET, et ne mentionne pas les corps de requête. Par conséquent, un serveur doit ignorer tout corps de requête qu'il reçoit sur une requête GET.

16
répondu izrik 2014-03-06 21:44:45

j'ai posé cette question au GT HTTP de L'IETF. Le commentaire de Roy Fielding (auteur du document http / 1.1 en 1998) était que

"... une implémentation serait rompue pour faire autre chose que d'analyser et de rejeter cet organisme si elle était reçue"

RFC 7213 (HTTPbis) states:

"Une charge utile dans un message de demande n'a pas de sémantique définie;"

il semble clair maintenant que l'intention était que le sens sémantique sur GET request bodies soit interdit, ce qui signifie que l'organisme de requête ne peut pas être utilisé pour affecter le résultat.

Il ya des mandataires là-bas qui seront certainement briser votre demande de diverses façons si vous inclure un corps sur GET.

donc en résumé, ne le faites pas.

13
répondu Adrien 2018-08-20 03:21:37

si vous voulez vraiment envoyer corps JSON/XML cachable à l'application web le seul endroit raisonnable pour mettre vos données est la chaîne de requête encodée avec RFC4648: Base 64 Encoding avec URL et L'Alphabet sûr de nom de fichier . Bien sûr, vous pouvez juste urlencode JSON et put est dans la valeur de L'URL param, mais Base64 donne un résultat plus petit. Gardez à l'esprit qu'il y a des restrictions de taille D'URL, voir Quelle est la longueur maximale d'une URL dans différents navigateurs? .

vous pouvez penser que le caractère de remplissage de Base64 = peut être mauvais pour la valeur param De URL, cependant il ne semble pas - voir cette discussion: http://mail.python.org/pipermail/python-bugs-list/2007-February/037195.html . Cependant, vous ne devriez pas mettre de données encodées sans nom param parce que la chaîne encodée avec le capitonnage sera interprétée comme une clé param avec une valeur vide. J'utiliserais quelque chose comme ?_b64=<encodeddata> .

7
répondu gertas 2017-05-23 12:10:54

je suis contrarié que le repos comme le protocole ne supporte pas OOP et la méthode Get en est la preuve. Comme solution, vous pouvez sérialiser votre DTO à JSON et ensuite créer une chaîne de requête. Du côté du serveur, vous pourrez désérialiser la chaîne de requête vers le DTO.

regardez:

L'approche basée sur les messages peut vous aider à résoudre obtenir la restriction de méthode. Vous pourrez envoyer n'importe quel DTO comme avec request body

nelibur Web Service framework fournit des fonctionnalités que vous pouvez utiliser

var client = new JsonServiceClient(Settings.Default.ServiceAddress);
var request = new GetClientRequest
    {
        Id = new Guid("2217239b0e-b35b-4d32-95c7-5db43e2bd573")
    };
var response = client.Get<GetClientRequest, ClientResponse>(request);

as you can see, the GetClientRequest was encoded to the following query string

http://localhost/clients/GetWithResponse?type=GetClientRequest&data=%7B%22Id%22:%2217239b0e-b35b-4d32-95c7-5db43e2bd573%22%7D
5
répondu GSerjo 2014-02-10 09:07:56

Qu'en est-il des en-têtes codés base64 non conformes? "SOMETHINGAPP-PARAMS: sdfSD45fdg45 / aS "

des restrictions de Longueur de hm. Ne pouvez-vous pas faire la distinction entre les significations? Si vous voulez paramètres simples comme le tri, je ne vois pas pourquoi ce serait un problème. Je suppose que c'est la certitude qui t'inquiète.

4
répondu chaz 2011-02-15 21:34:57

IMHO vous pouvez simplement envoyer le JSON encodé (c.-à-d. encodeURIComponent ) dans le URL , de cette façon vous ne violez pas le HTTP specs et obtenez votre JSON au serveur.

4
répondu EthraZa 2015-04-27 19:18:59

selon XMLHttpRequest, il n'est pas valide. De la standard :

4.5.6 la " méthode 151910920

client . send([body = null])

déclenche la requête. L'argument optionnel fournit la requête corps. L'argument est ignoré si la méthode de requête est GET ou HEAD .

lance une exception InvalidStateError si l'un ou l'autre des États est pas ouvert ou la send() le drapeau est réglé.

la méthode send(body) doit suivre ces étapes:

  1. Si l'état n'est pas ouvert , de lancer un InvalidStateError l'exception".
  2. si le drapeau send() est activé, lancer une exception InvalidStateError .
  3. si la méthode de requête est GET ou HEAD , définir corps à null.
  4. si body est nul, passer à l'étape suivante.

bien que, je ne pense pas qu'il devrait parce que obtenir la demande pourrait avoir besoin de gros contenu de corps.

donc, si vous vous fiez à XMLHttpRequest d'un navigateur, il est probable que cela ne fonctionnera pas.

4
répondu Rafael Sales 2016-05-04 20:51:46

Je ne conseillerais pas cela, cela va à l'encontre des pratiques standard, et n'offre pas autant en retour. Vous voulez garder le corps pour le contenu, pas des options.

3
répondu cloudhead 2009-06-10 20:56:09

par exemple, il fonctionne avec Curl, Apache et PHP.

fichier PHP:

<?php
echo $_SERVER['REQUEST_METHOD'] . PHP_EOL;
echo file_get_contents('php://input') . PHP_EOL;

de la Console de commande:

$ curl -X GET -H "Content-Type: application/json" -d '{"the": "body"}' 'http://localhost/test/get.php'

sortie:

GET
{"the": "body"}
3
répondu mnv 2015-11-20 22:16:01