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?
Réponses:
Commentaire de Roy Fielding sur l'inclusion d'un corps avec une demande GET .
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 :
Et la description de la méthode GET dans la spécification HTTP / 1.1, section 9.3 :
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
la source
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.
la source
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.
la source
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
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
et la section 9.3 dit
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.
la source
GET /contacts/100/addresses
retourne une collection d'adresses pour la personne avecid=100
.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.
la source
curl -XGET 'http://localhost:9200/_count?pretty' -d ' { "query": { "match_all": {} } }'
équivaut à inclure la charge utile en tant quesource
paramètre:curl -XGET 'http://localhost:9200/_count?pretty&source=%7B%22query%22%3A%7B%22match_all%22%3A%7B%7D%7D%7D'
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.
la source
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):
Clients pouvant envoyer un GET avec body:
Serveurs et bibliothèques pouvant récupérer un corps depuis GET:
Serveurs (et mandataires) qui suppriment un corps de GET:
la source
SEARCH
mé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 ...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:
(le contenu 1234 est suivi de CR-LF, ce qui fait un total de 6 octets)
et vous obtiendrez:
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.
la source
GET
requê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.GET
point de terminaison particulier - cela n'a rien à voir avec l'utilisation deGET
dans le cas général. Une charge utile aléatoire pourrait casser unPOST
tout aussi facilement, et retourner le même400 Bad Request
, si le contenu n'était pas dans un format qui avait du sens dans le contexte de la demande spécifique.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
La RFC 7213 (HTTPbis) indique:
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.
la source
De RFC 2616, section 4.3 , «Corps du message»:
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.
la source
Selon XMLHttpRequest, ce n'est pas valide. De la norme :
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.
la source
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>
.la source
Vary
tête, je n'étais pas conscient de son réel potentiel.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.
la source
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.
la source
x-
préfixe, toute limite sur la longueur des en-têtes serait entièrement une limite arbitraire du serveur.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
la source
Par exemple, il fonctionne avec Curl, Apache et PHP.
Fichier PHP:
Commande de la console:
Production:
la source
$_POST
lorsque le corps sera envoyé avec une requête POST etapplication/x-www-form-urlencoded
. Cela signifie que le corps est ignoré dans uneGET
demande. Dans ce cas:$_GET
et$_POST
sont de toute façon très trompeurs à ce stade. Donc une meilleure utilisationphp://input
À mon humble avis, vous pouvez simplement envoyer le
JSON
codé (c'est-à-direencodeURIComponent
) dans leURL
, de cette façon, vous ne violez pas lesHTTP
spécifications et obtenez votreJSON
au serveur.la source
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:
example.com/category/{catid}/item/{itemid}?sortby=itemname&order=asc
example.com/category/{catid}/item/{itemid}/{sortby}/{order}
Tous ont leurs inconvénients, mais sont bien meilleurs que d'utiliser un GET avec un corps.
la source
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 :
Et oui, vos bibliothèques clientes peuvent également ne pas prendre en charge l'émission de telles demandes, comme indiqué dans ce commentaire .
la source
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:
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.
la source