HTTP GET avec corps de demande

2112

Je développe un nouveau webservice RESTful pour notre application.

Lors d'une opération GET sur certaines entités, les clients peuvent demander le contenu de l'entité. S'ils souhaitent ajouter des paramètres (par exemple, trier une liste), ils peuvent ajouter ces paramètres dans la chaîne de requête.

Sinon, je veux que les gens puissent spécifier ces paramètres dans le corps de la demande. 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 tout à fait?
  • Les clients HTTP auront-ils des problèmes avec l'utilisation des corps de demande dans une demande GET?

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

Evert
la source
553
L'avantage est qu'il permet d'envoyer facilement des corps de requête XML ou JSON, qu'il n'a pas de restriction de longueur et qu'il est plus facile à encoder (UTF-8).
Evert le
29
Si ce que vous recherchez est une méthode sûre et idempotente qui autorise les corps de requête, vous voudrez peut-être regarder SEARCH, PROPFIND et REPORT. Bien sûr, ne pas utiliser GET et avoir un corps de requête défait plus ou moins la mise en cache.
Julian Reschke
226
@fijiaaron: C'est 3 ans plus tard, et depuis lors, j'ai acquis une vaste expérience dans l'écriture de services Web. C'est essentiellement tout ce que je fais depuis quelques années. Je peux dire en toute sécurité, c'est en effet une très mauvaise idée d'ajouter un corps à une demande GET. Les deux premières réponses sont comme un rocher.
Evert
26
@Ellesedil: Autrement dit: quels que soient les avantages de l'utilisation de GET sur POST, ils existent en raison de la conception de HTTP. Ces avantages n'existent plus lorsque vous violez la norme de cette manière. Par conséquent, il n'y a qu'une seule raison d'utiliser GET + un corps de demande au lieu de POST: l'esthétique. Ne sacrifiez pas la conception robuste à l'esthétique.
Evert
7
Pour souligner ce qu'a dit Evert: "il n'y a pas de restriction de longueur". Si votre GET avec des paramètres de requête rompt la restriction de longueur (sur 2048), alors quel autre choix est là autre que de mettre les informations de la chaîne de requête dans un objet json, par exemple, dans le corps de la demande.
Kieran Ryan

Réponses:

1726

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 en gardant cela à l'esprit. Cependant, la sémantique du serveur pour GET est limitée de telle sorte qu'un corps, le cas échéant, n'a aucune signification sémantique pour la demande. Les exigences relatives à l'analyse sont distinctes des exigences relatives à la sémantique des méthodes.

Donc, oui, vous pouvez envoyer un corps avec GET, et non, ce n'est jamais utile de le faire.

Cela fait partie de la conception en couches de HTTP / 1.1 qui redeviendra claire une fois la spécification partitionnée (travail en cours).

.... Roy

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

[...] si la méthode de demande n'inclut pas de sémantique définie pour un corps d'entité, alors le corps de message DEVRAIT être ignoré lors du traitement de la demande.

Et la description de la méthode GET dans la spécification HTTP / 1.1, section 9.3 :

La méthode GET signifie récupérer toutes les informations ([...]) identifiées par l'URI de demande.

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

Mise à jour Le RFC2616 référencé comme "spécification HTTP / 1.1" est désormais obsolète. En 2014, il a été remplacé par les RFC 7230-7237. La citation "le corps du message DEVRAIT être ignoré lors du traitement de la demande" a été supprimée. C'est maintenant juste "Le cadrage du message de demande est indépendant de la sémantique de la méthode, même si la méthode ne définit aucune utilisation pour un corps de message" La deuxième citation "La méthode GET signifie récupérer toutes les informations ... est identifiée par l'URI de la demande" A été supprimée. - D'un commentaire

Paul Morgan
la source
72
La mise en cache / proxy est les deux choses que vous êtes le plus susceptible de casser, oui. La «sémantique» n'est qu'une autre façon de dire «la façon dont les gens qui fabriquent d'autres composants s'attendront à ce que d'autres composants fonctionnent». Si vous violez la sémantique, vous êtes plus susceptible de voir des choses se briser dans des endroits où les gens ont écrit des choses qui s'attendaient à ce que vous respectiez cette sémantique.
Stuart P. Bentley
109
Elasticsearch est un produit assez important qui utilise les corps de requête HTTP dans GET. Selon leur manuel, la question de savoir si une requête HTTP doit prendre en charge le fait d'avoir un corps ou non n'est pas définie. Personnellement, je ne suis pas à l'aise de remplir un corps de demande GET, mais ils semblent avoir une opinion différente et ils doivent savoir ce qu'ils font. elastic.co/guide/en/elasticsearch/guide/current/…
GordonM
26
@iwein donner un sens aux organes de requête GET n'est en fait pas une violation de la spécification. HTTP / 1.1 spécifie que les serveurs DEVRAIENT ignorer le corps, mais la RFC 2119 spécifie que les implémenteurs sont autorisés à ignorer les clauses "DEVRAIENT" s'ils ont de bonnes raisons de le faire. , Un client plutôt fait violer la spécification si elle suppose que la modification du corps GET va pas changer la réponse.
Emil Lundberg
108
Le RFC2616 référencé comme "spécification HTTP / 1.1" est désormais obsolète. En 2014, il a été remplacé par les RFC 7230-7237. La citation " le corps du message DEVRAIT être ignoré lors du traitement de la demande " a été supprimée . C'est maintenant juste "Le cadrage du message de demande est indépendant de la sémantique de la méthode, même si la méthode ne définit aucune utilisation pour un corps de message " La 2ème citation " La méthode GET signifie récupérer toutes les informations ... est identifiée par l'URI de la demande " a été supprimé . Donc, je suggère de modifier la réponse @Jarl
Artem Nakonechny
29
Je sais que c'est un vieux fil - je suis tombé dessus. @Artem Nakonechny a techniquement raison, mais la nouvelle spécification dit "Une charge utile dans un message de demande GET n'a pas de sémantique définie; l'envoi d'un corps de charge utile sur une demande GET peut entraîner le rejet de la demande par certaines implémentations existantes." Ce n'est donc pas une très bonne idée si on peut l'éviter.
fastcatch
290

Bien que vous puissiez le faire, dans la mesure où cela n'est pas explicitement exclu par la spécification HTTP, je suggère 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 "principalement" conformes à la spécification HTTP, la seule chose dont vous êtes assuré est qu'elles se comporteront comme traditionnellement utilisées par les navigateurs Web. (Je pense à des choses comme des proxys transparents, des accélérateurs, des kits d'outils A / V, etc.)

C'est l'esprit qui sous-tend le principe de robustesse: "soyez 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 raison valable.

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

caskey
la source
229
Le principe de robustesse est défectueux. Si vous êtes libéral dans ce que vous acceptez, vous obtiendrez de la merde, si vous avez du succès en termes d'adoption, simplement parce que vous acceptez la merde. Cela rendra plus difficile l'évolution de votre interface. Regardez simplement HTML. C'est le principe de la répulsion en action.
Eugene Beresovsky
28
Je pense que le succès et l'ampleur de l'adoption (et des abus) des protocoles témoignent de la valeur du principe de robustesse.
caskey
39
Avez-vous déjà essayé d'analyser du vrai HTML? Il n'est pas possible de l'implémenter vous-même, c'est pourquoi presque tout le monde - y compris les très grands acteurs comme Google (Chrome) et Apple (Safari), ne l'ont pas fait mais se sont appuyés sur des implémentations existantes (au final, ils se sont tous appuyés sur KHTML de KDE). Cette réutilisation est bien sûr agréable, mais avez-vous essayé d'afficher du HTML dans une application .net? C'est un cauchemar, car vous devez soit incorporer un composant IE (non géré) (ou similaire), avec ses problèmes et plantages, soit utiliser le composant géré disponible (sur codeplex) qui ne vous permet même pas de sélectionner du texte.
Eugene Beresovsky
6
Non seulement la spécification HTTP autorise les données de corps avec une requête GET, mais c'est aussi une pratique courante: l'API _search du moteur ElasticSearch populaire recommande les requêtes GET avec la requête attachée dans un corps JSON. En tant que concession aux implémentations client HTTP incomplètes, il autorise également les requêtes POST ici.
Christian Pietsch
4
@ChristianPietsch, c'est une pratique courante aujourd'hui. Il y a quatre ans, ce n'était pas le cas. Bien que la spécification autorise explicitement un client à inclure (PEUT) facultativement une entité dans une demande (section 7), la signification de MAI est définie dans la RFC2119 et un serveur proxy (merdique) pourrait être conforme aux spécifications tout en supprimant les entités dans les demandes GET, spécifiquement tant qu'il ne plante pas, il peut fournir une «fonctionnalité réduite» en transmettant les en-têtes de demande et non l'entité incluse. De même, il existe une multitude de règles sur les changements de version qui DOIVENT / PEUVENT / DEVRAIENT être effectués lors du proxy entre différents niveaux de protocole.
caskey
151

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

Darrel Miller
la source
10
L'utilisation des champs d'en-tête ETag / Last-Modified aide de cette manière: lorsqu'un "GET conditionnel" est utilisé, les mandataires / caches peuvent agir sur ces informations.
jldupont
2
@jldupont Les caches utilisent la présence de validateurs pour savoir si une réponse périmée peut être revalidée, cependant, ils ne sont pas utilisés dans le cadre de la clé de cache principale ou secondaire.
Darrel Miller
Vous pouvez corriger cela avec une somme de contrôle du corps dans un paramètre de requête
Adrian May
73

Ni restclient ni la console REST ne prennent en charge cela, mais curl le fait.

La spécification HTTP dit dans la section 4.3

Un corps de message NE DOIT PAS être inclus dans une demande si la spécification de la méthode de demande (section 5.1.1) ne permet pas d'envoyer un corps d'entité dans les demandes.

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

La section 5.2 dit

La ressource exacte identifiée par une demande Internet est déterminée en examinant à la fois l'URI de la demande et le champ d'en-tête Host.

et la section 9.3 dit

La méthode GET signifie récupérer toutes les informations (sous la forme d'une entité) identifiées par l'URI de demande.

Ce qui, ensemble, suggère que lors du traitement d'une demande GET, un serveur n'est pas tenu d'examiner autre chose que le champ d'en-tête Request-URI et Host.

En résumé, la spécification HTTP ne vous empêche pas d'envoyer un corps de message avec GET mais il y a suffisamment d'ambiguïté pour que cela ne m'étonne pas s'il n'était pas pris en charge par tous les serveurs.

Dave Durbin
la source
2
Paw a également la possibilité de prendre en charge les demandes GET avec les corps, mais il doit être activé dans les paramètres.
s.Daniel
"La méthode GET signifie récupérer toutes les informations (sous la forme d'une entité) qui sont identifiées par l'URI de demande." Alors, est-il techniquement illégal / faux d'avoir un point d'extrémité GET qui obtient toutes les entités? Par exemple, GET /contacts/100/addressesretourne une collection d'adresses pour la personne avec id=100.
Josh M.
La bibliothèque Java rassurée pour tester les API REST ne prend pas en charge la requête GET avec un corps. Apache HttpClient ne le prend pas non plus en charge.
Paulo Merson
Django prend également en charge l'analyse d'un corps GET
Bruno Finger
60

Elasticsearch accepte les requêtes GET avec un corps. Il semble même que ce soit la voie préférée: Elasticsearch guide

Certaines bibliothèques clientes (comme le pilote Ruby) peuvent consigner la commande cry sur stdout en mode développement et elle utilise largement cette syntaxe.

jlecour
la source
5
Je me demandais pourquoi Elasticsearch le permet. Cela signifie que cette requête pour compter tous les documents avec une charge utile dans une demande GET curl -XGET 'http://localhost:9200/_count?pretty' -d ' { "query": { "match_all": {} } }' équivaut à inclure la charge utile en tant que sourceparamètre: curl -XGET 'http://localhost:9200/_count?pretty&source=%7B%22query%22%3A%7B%22match_all%22%3A%7B%7D%7D%7D'
arun
40
Les requêtes complexes peuvent atteindre la longueur maximale de l'en-tête http.
s.Daniel
11
C'est la lecture de la documentation elasticsearch qui m'a
amené
1
Il n'a même pas besoin d'être une requête complexe. Même un simple défilement peut renvoyer un très long scroll_id (dans un cluster avec de nombreux fragments), ce qui entraînera un dépassement de la longueur maximale de l'URL s'il y est ajouté.
Brent Hronik
11
Elasticsearch prend en charge la même demande à l'aide de POST. Ils ont seulement choisi d'autoriser un corps dans un GET parce qu'ils pensaient qu'un GET est plus sémantiquement correct qu'un POST lorsqu'il s'agit d'interroger des données. C'est drôle qu'Elasticsearch soit tellement mentionné dans ce fil. Je n'utiliserais pas un exemple (bien qu'il s'agisse d'un produit populaire) comme raison de suivre la pratique.
DSO
33

Ce que vous essayez d'atteindre a été 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 créer votre type de recherche spécifique, ou si vous voulez être plus RESTful, utilisez quelque chose comme OpenSearch et POSTEZ la demande à l'URI que le serveur a demandé, par exemple / search. Le serveur peut ensuite générer le résultat de la recherche ou créer l'URI final et rediriger à l'aide d'un 303.

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

Cela dit, les URI sont de toute façon encodés pour tout ce qui n'est pas ASCII, tout comme application / x-www-form-urlencoded et multipart / form-data. Je recommanderais d'utiliser cela plutôt que de créer un autre format json personnalisé si votre intention est de prendre en charge les scénarios ReSTful.

SerialSeb
la source
4
Vous pouvez simplement créer votre type de recherche spécifique. Pourriez-vous élaborer?
Piotr Dobrogost
2
Par cela, je disais que vous pouviez créer un type de média appelé application / vnd.myCompany.search + json qui contiendrait le type de modèle de recherche que vous souhaitez qu'un client émette, et le client pourrait ensuite l'envoyer en tant que POST. Comme je l'ai souligné, il existe déjà un type de média pour cela et il s'appelle OpenSearch, la réutilisation d'un type de média existant doit être choisie sur l'itinéraire personnalisé lorsque vous pouvez implémenter votre scénario avec les normes existantes.
SerialSeb
14
C'est intelligent, mais trop complexe et inefficace. Maintenant, vous devez envoyer un POST avec vos critères de recherche, obtenir un URI en tant que réponse de votre POST, puis envoyer un GET avec l'URI des critères de recherche au serveur pour qu'il le reçoive et obtenir le résultat. (Sauf qu'inclure un URI dans un URI est techniquement impossible car vous ne pouvez pas envoyer quelque chose qui peut contenir jusqu'à 255 caractères dans quelque chose qui ne peut pas dépasser 255 caractères - vous devez donc utiliser un identifiant partiel et votre serveur ensuite a besoin de savoir comment résoudre l'URI pour vos critères de recherche POSTés.)
fijiaaron
30

Vous pouvez 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 liés ci-dessus).

Les décisions ne sont pas non plus importantes, mais l'envoi d'un corps GET peut éviter des problèmes pour certains clients - et certains serveurs.

Faire un POST peut avoir des obstacles avec certains frameworks RESTish.

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

Il pourrait être plus productif d'énumérer les clients qui peuvent et ne peuvent pas faire chacun des éléments ci-dessus.

Clients qui ne peuvent pas envoyer de GET avec corps (à ma connaissance):

  • XmlHTTPRequest Fiddler

Clients pouvant envoyer un GET avec body:

  • la plupart des navigateurs

Serveurs et bibliothèques pouvant récupérer un corps depuis GET:

  • Apache
  • PHP

Serveurs (et mandataires) qui suppriment un corps de GET:

  • ?
fijiaaron
la source
2
Squid 3.1.6 supprime également les corps GET lorsque Content-Length est 0 ou non défini, et renvoie sinon une longueur HTTP 411 requise même si la longueur est définie
rkok
2
Fiddler le fera, mais il vous avertit.
toddmo
Êtes-vous en train de dire qu'une SEARCHméthode risquerait de casser en cours de route? Si les mandataires ne comprennent pas une méthode, ils sont censés la passer telle quelle, donc je ne sais pas trop pourquoi vous pensez que cela casserait quoi que ce soit ...
Alexis Wilke
22

Quel serveur l'ignorera? - fijiaaron 30 août 12 à 21:27

Google, par exemple, fait pire que de l'ignorer, il considérera que c'est 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 1234 est suivi de CR-LF, ce qui fait 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 obtenez également 400 Bad Request de Bing, Apple, etc ... qui sont servis par AkamaiGhost.

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

user941239
la source
66
Cet exemple est inutile car généralement lorsque les gens vont ajouter du corps aux GETrequêtes, c'est parce que leur propre serveur personnalisé est capable de le gérer. La question est donc de savoir si les autres "parties mobiles" (navigateurs, caches, etc.) fonctionneront correctement.
Pacerier
6
Il s'agit d'une mauvaise requête car votre charge utile n'est pas attendue (ou sensible) pour un GET point de terminaison particulier - cela n'a rien à voir avec l'utilisation de GETdans le cas général. Une charge utile aléatoire pourrait casser un POSTtout aussi facilement, et retourner le même 400 Bad Request, si le contenu n'était pas dans un format qui avait du sens dans le contexte de la demande spécifique.
nobar
Et pas seulement sur ce point de terminaison dans son ensemble, mais plutôt sur cette URL spécifique .
Lawrence Dol
1
Cela n'est pas pertinent car il s'agit simplement de l'implémentation du serveur de Google à cette URL. Cela n'a donc aucun sens à la question
Joel Duckworth
pour moi, cela a été utile, car j'essayais d'utiliser des fonctions Firebase avec une requête get + body, et cette erreur peut être très cryptique et difficile à comprendre.
scrimau
22

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

"... une implémentation serait interrompue pour faire autre chose que d'analyser et de jeter ce corps s'il était reçu"

La RFC 7213 (HTTPbis) indique:

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

Il semble clair maintenant que l'intention était d'interdire la signification sémantique sur les corps de demande GET, ce qui signifie que le corps de demande ne peut pas être utilisé pour affecter le résultat.

Il existe des procurations qui briseront définitivement votre demande de différentes manières si vous incluez un corps sur GET.

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

Adrien
la source
19

De RFC 2616, section 4.3 , «Corps du message»:

Un serveur DEVRAIT lire et transmettre un corps de message sur toute demande; si la méthode de demande n'inclut pas de sémantique définie pour un corps d'entité, alors le corps du message DEVRAIT être ignoré lors du traitement de la demande.

Autrement dit, les serveurs doivent toujours lire tout corps de demande fourni à partir du réseau (vérifiez Content-Length ou lisez un corps fragmenté, etc.). En outre, les mandataires doivent transmettre tout corps de demande qu'ils reçoivent. Ensuite, si la RFC définit la sémantique du corps pour la méthode donnée, le serveur peut réellement utiliser le corps de la requête pour générer une réponse. Cependant, si le RFC ne définit pas de sémantique pour le corps, le serveur doit l'ignorer.

Ceci est conforme à la citation de Fielding ci-dessus.

La 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 demande qu'il reçoit sur une demande GET.

izrik
la source
La section 9.5 , "POST", ne mentionne pas non plus les corps de demande, donc cette logique est défectueuse.
CarLuva
9
@CarLuva La section POST indique "La méthode POST est utilisée pour demander au serveur d'origine d'accepter l'entité incluse ..." La section de corps d'entité dit "Le corps d'entité est obtenu à partir du corps de message ..." Par conséquent, le La section POST mentionne le corps du message, bien qu'indirectement en référençant le corps d'entité qui est porté par le corps du message de la demande POST.
frederickf
9

Selon XMLHttpRequest, ce n'est pas valide. De la norme :

4.5.6 La send()méthode

client . send([body = null])

Lance la demande. L'argument facultatif fournit le corps de la demande. L'argument est ignoré si la méthode de demande est GETou HEAD.

Lève une InvalidStateErrorexception si l'un des états n'est pas ouvert ou si l' send()indicateur est défini.

La méthode doit exécuter ces étapes:send(body)

  1. Si l'état n'est pas ouvert , lève une InvalidStateErrorexception.
  2. Si l' send()indicateur est défini, lancez une InvalidStateErrorexception.
  3. Si la méthode de demande est GETor HEAD, définissez body sur null.
  4. Si le corps est nul, passez à l'étape suivante.

Cependant, je ne pense pas que ce soit le cas, car la demande GET peut nécessiter un contenu volumineux.

Donc, si vous comptez sur XMLHttpRequest d'un navigateur, il est probable que cela ne fonctionnera pas.

Rafael Sales
la source
1
downvoted en raison du fait que XMLHttpRequest est une implémentation. Il peut ne pas refléter la spécification réelle qu'il est censé implémenter.
floum
10
Downvote ci-dessus est faux, si certaines implémentations ne prennent pas en charge l'envoi d'un corps avec un GET, cela peut être une raison pour ne pas le faire, quelle que soit la spécification. En fait, j'ai rencontré ce problème exact dans un produit multiplateforme sur lequel je travaille - seule la plate-forme utilisant XMLHttpRequest n'a pas pu envoyer le get.
pjcard
8

Si vous voulez vraiment envoyer un corps JSON / XML cachable à une application Web, le seul endroit raisonnable pour mettre vos données est la chaîne de requête encodée avec RFC4648: Encodage Base 64 avec URL et nom de fichier Safe Alphabet . Bien sûr, vous pouvez simplement encoder JSON en url et mettre dans la valeur du paramètre URL, mais Base64 donne un résultat plus petit. Gardez à l'esprit qu'il existe 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 de paramètre d'URL, mais il ne semble pas - voir cette discussion: http://mail.python.org/pipermail/python-bugs-list/2007-F February / 037195.html . Cependant, vous ne devez pas mettre de données codées sans nom de paramètre, car une chaîne codée avec un remplissage sera interprétée comme une clé de paramètre avec une valeur vide. J'utiliserais quelque chose comme ?_b64=<encodeddata>.

gertas
la source
Je pense que c'est une assez mauvaise idée :) Mais si je faisais quelque chose comme ça, j'utiliserais à la place un en-tête HTTP personnalisé (et m'assurer de toujours renvoyer Vary: dans la réponse).
Evert le
Mauvais ou pas mais faisable :) Avec les données dans l'en-tête, il y a un problème similaire avec la taille des données, voir stackoverflow.com/questions/686217/… . Cependant, merci d'avoir mentionné l'en- Varytête, je n'étais pas conscient de son réel potentiel.
gertas
6

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

cloudhead
la source
5

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

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

chaz
la source
Vous pouvez envoyer tous les paramètres que vous voulez avec le x-préfixe, toute limite sur la longueur des en-têtes serait entièrement une limite arbitraire du serveur.
Chris Marisic
4

Je suis contrarié par le fait que REST car le protocole ne prend pas en charge la POO et Get méthode en est la preuve. Comme solution, vous pouvez sérialiser votre DTO en JSON puis créer une chaîne de requête. Côté serveur, vous pourrez désérialiser la chaîne de requête vers le DTO.

Jetez un oeil sur:

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

La structure de service Web Nelibur 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
GSerjo
la source
8
Vous devez simplement utiliser POST. S'il y a un nom de méthode dans l'URL, vous violez la conception fondamentale du repos. C'est RPC, utilisez POST.
Evert
3
Je ne pense pas que ce soit un gros problème, nous avons plus de problèmes lors du développement avec l'URL RESTful (ie commandes / 1). Quant à moi, quelque chose de mal avec la méthode Get, c'est incompatible avec la POO. Et peu importe à quoi ressemble l'URL :) Mais avec une approche basée sur les messages, nous pouvons créer une interface distante stable et c'est vraiment important. PS ce n'est pas RPC, c'est basé sur un message
GSerjo
3
Je pense que vous manquez tout l'intérêt de REST. Quand vous dites, qui se soucie de l'apparence de l'URL, REST se soucie beaucoup. Et pourquoi REST serait-il compatible avec la POO?
shmish111
Non, je ne l'ai pas vu un peu plus loin
GSerjo
4

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;

Commande de la console:

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

Production:

GET
{"the": "body"}
mnv
la source
Expérience amusante! PHP ne lira que $_POSTlorsque le corps sera envoyé avec une requête POST et application/x-www-form-urlencoded. Cela signifie que le corps est ignoré dans une GETdemande. Dans ce cas: $_GETet $_POSTsont de toute façon très trompeurs à ce stade. Donc une meilleure utilisationphp://input
Martin Muzatko
3

À mon humble avis, vous pouvez simplement envoyer le JSONcodé (c'est-à-dire encodeURIComponent) dans le URL, de cette façon, vous ne violez pas les HTTPspécifications et obtenez votre JSONau serveur.

EthraZa
la source
28
oui mais le problème majeur est la longueur limite, comment pouvons-nous y faire face?
Sebas
2

Vous avez une liste d'options bien meilleures que l'utilisation d'un corps de requête avec GET.

Supposons que vous ayez des catégories et des éléments pour chaque catégorie. Les deux doivent être identifiés par un identifiant ("catid" / "itemid" pour cet exemple). Vous souhaitez trier selon un autre paramètre "sortby" dans un "ordre" spécifique. Vous voulez passer des paramètres pour "sortby" et "order":

Vous pouvez:

  1. Utilisez des chaînes de requête, par exemple example.com/category/{catid}/item/{itemid}?sortby=itemname&order=asc
  2. Utilisez mod_rewrite (ou similaire) pour les chemins: example.com/category/{catid}/item/{itemid}/{sortby}/{order}
  3. Utilisez les en-têtes HTTP individuels que vous transmettez avec la demande
  4. Utilisez une méthode différente, par exemple POST, pour récupérer une ressource.

Tous ont leurs inconvénients, mais sont bien meilleurs que d'utiliser un GET avec un corps.

Xénonite
la source
0

Même si un outil populaire utilise cela, comme souvent cité sur cette page, je pense que c'est quand même une assez mauvaise idée, étant trop exotique, malgré ce qui n'est pas interdit par la spécification.

De nombreuses infrastructures intermédiaires peuvent simplement rejeter de telles demandes.

Par exemple, oubliez d'utiliser certains des CDN disponibles devant votre site Web, comme celui- ci :

Si une GETdemande de visualiseur inclut un corps, CloudFront renvoie un code de statut HTTP 403 (interdit) au visualiseur.

Et oui, vos bibliothèques clientes peuvent également ne pas prendre en charge l'émission de telles demandes, comme indiqué dans ce commentaire .

Frédéric
la source
0

J'utilise RestTemplate du framework Spring dans mon programme client et, côté serveur, j'ai défini une requête GET avec un corps Json. Mon objectif principal est le même que le vôtre: lorsque la demande a de nombreux paramètres, les mettre dans le corps semble plus ordonné que de les mettre dans la chaîne d'URI prolongée. Oui?

Mais, malheureusement, cela ne fonctionne pas! Le côté serveur a levé l'exception suivante:

org.springframework.http.converter.HttpMessageNotReadableException: le corps de demande requis est manquant ...

Mais je suis sûr que le corps du message est correctement fourni par mon code client, alors qu'est-ce qui ne va pas?

J'ai tracé la méthode RestTemplate.exchange () et trouvé ce qui suit:

// SimpleClientHttpRequestFactory.class
public class SimpleClientHttpRequestFactory implements ClientHttpRequestFactory, AsyncClientHttpRequestFactory {
    ...
    protected void prepareConnection(HttpURLConnection connection, String httpMethod) throws IOException {
        ...
        if (!"POST".equals(httpMethod) && !"PUT".equals(httpMethod) && !"PATCH".equals(httpMethod) && !"DELETE".equals(httpMethod)) {
            connection.setDoOutput(false);
        } else {
            connection.setDoOutput(true);
        }
        ...
    }
}

// SimpleBufferingClientHttpRequest.class
final class SimpleBufferingClientHttpRequest extends AbstractBufferingClientHttpRequest {
    ...
    protected ClientHttpResponse executeInternal(HttpHeaders headers, byte[] bufferedOutput) throws IOException {
        ...
        if (this.connection.getDoOutput() && this.outputStreaming) {
            this.connection.setFixedLengthStreamingMode(bufferedOutput.length);
        }

        this.connection.connect();
        if (this.connection.getDoOutput()) {
            FileCopyUtils.copy(bufferedOutput, this.connection.getOutputStream());
        } else {
            this.connection.getResponseCode();
        }
        ...
    }
}

Veuillez noter que dans la méthode executeInternal (), l'argument d'entrée 'bufferedOutput' contient le corps du message fourni par mon code. Je l'ai vu à travers le débogueur.

Cependant, en raison de prepareConnection (), le getDoOutput () dans executeInternal () renvoie toujours false ce qui, à son tour, rend le bufferedOutput complètement ignoré! Il n'est pas copié dans le flux de sortie.

Par conséquent, mon programme serveur n'a reçu aucun corps de message et a levé cette exception.

Ceci est un exemple sur le RestTemplate du framework Spring. Le fait est que, même si le corps du message n'est plus interdit par la spécification HTTP, certaines bibliothèques ou infrastructures client ou serveur peuvent toujours se conformer à l'ancienne spécification et rejeter le corps du message de la demande GET.

Zhou
la source
Vous ne lisez pas correctement les spécifications ou les commentaires. Les clients et serveurs supprimant le corps de la demande sont conformes aux spécifications. N'utilisez pas les corps de requête GET.
Evert
@Evert, je n'ai pas lu les commentaires correctement ou vous ne l'avez pas fait? :) Si vous faites défiler vers le haut jusqu'à la réponse de Paul Morgan (la réponse la plus frappée) et lisez attentivement les commentaires, vous trouverez ceci: "Le RFC2616 référencé comme" spécification HTTP / 1.1 "est maintenant obsolète. En 2014, il a été remplacé par RFC 7230-7237. La citation "le corps du message DEVRAIT être ignoré lors du traitement de la demande" a été supprimée. Il s'agit désormais simplement de "Le cadrage du message de demande est indépendant de la sémantique de la méthode, même si la méthode ne définit aucune utilisation pour un corps de message ... "
Zhou
@Evert De plus, j'utilisais l'utilitaire de test REST "rassuré" pour tester mon backend Spring-boot. À la fois rassurés et côté serveur Spring-boot, le corps Json a été conservé pour la demande GET! Seul le RestTemplate du framework Sping supprime le corps des requêtes GET, donc Spring-boot, rest-sure et RestTemplate, qui est / sont faux?
Zhou
@Evert Last but not bail, je n'ai pas exhorté les gens à utiliser le corps dans les requêtes GET, au contraire, je proposais de ne PAS le faire en analysant le code source du RestTemplate du cadre Sping, alors pourquoi avez-vous voté contre mon réponse?
Zhou
Je n'ai pas diminué votre réponse. Je précise simplement que toute implémentation HTTP supprimant une demande GET est conforme aux spécifications.
Evert