POST HTTP avec paramètres de requête URL - bonne idée ou pas? [fermé]

451

Je conçois une API pour parcourir HTTP et je me demande si l'utilisation de la commande HTTP POST, mais avec des paramètres de requête URL uniquement et sans corps de demande, est une bonne façon de procéder.

Considérations:

  • Une «bonne conception Web» requiert que des actions non idempotentes soient envoyées via POST. Il s'agit d'une action non idempotente.
  • Il est plus facile de développer et de déboguer cette application lorsque les paramètres de demande sont présents dans l'URL.
  • L'API n'est pas destinée à une utilisation généralisée.
  • Il semble que faire une requête POST sans corps prendra un peu plus de travail, par exemple un en- Content-Length: 0tête doit être explicitement ajouté.
  • Il me semble également qu'un POST sans corps est un peu contraire aux attentes de la plupart des développeurs et des frameworks HTTP.

Y a-t-il d'autres pièges ou avantages à envoyer des paramètres sur une requête POST via la requête URL plutôt que le corps de la requête?

Edit: La raison pour laquelle cela est envisagé est que les opérations ne sont pas idempotentes et ont des effets secondaires autres que la récupération. Voir la spécification HTTP :

En particulier, la convention a été établie que les méthodes GET et HEAD NE DEVRAIENT PAS avoir la signification de prendre une action autre que la récupération. Ces méthodes doivent être considérées comme «sûres». Cela permet aux agents utilisateurs de représenter d'autres méthodes, telles que POST, PUT et DELETE, d'une manière spéciale, afin que l'utilisateur soit informé du fait qu'une action potentiellement dangereuse est demandée.

...

Les méthodes peuvent également avoir la propriété d '"idempotence" en ce que (à part les problèmes d'erreur ou d'expiration) les effets secondaires de N> 0 requêtes identiques sont les mêmes que pour une seule requête. Les méthodes GET, HEAD, PUT et DELETE partagent cette propriété. De plus, les méthodes OPTIONS et TRACE NE DEVRAIENT PAS avoir d'effets secondaires et sont donc intrinsèquement idempotentes.

Steven Huwig
la source
11
Pourquoi utiliser POST si vous ne fournissez pas de données dans le corps?
Sunny Milenov
114
Parce que l'opération n'est pas idempotente.
Steven Huwig
20
@Jared, notez que le mot "REST" n'apparaît pas dans cette question il y a 2,5 ans. :) La spécification HTTP sur l'idempotence s'applique quelle que soit l'architecture de la saveur du mois pour les services Web. Heureusement, le système pour lequel cette API a été conçue pour être proxy a été rendu obsolète de toute façon.
Steven Huwig
5
Parce que les journaux du serveur n'enregistrent pas les paramètres POST, mais ils enregistrent les chaînes de requête. Il est beaucoup plus facile d'exécuter la série de demandes sans l'instruire dans le navigateur, puis de regarder la trace, que de cliquer dessus. L'API n'était pas non plus du navigateur au serveur, mais plutôt du serveur au serveur. Plus important encore, toute l'affaire a été mise en conserve de toute façon. :)
Steven Huwig
13
Pour toute autre personne qui ne sait pas ce que signifie idempotent: | restapitutorial.com/lessons/idempotency.html
Christopher Grigg

Réponses:

259

Si votre action n'est pas idempotente, alors vous DEVEZ l' utiliser POST. Si vous ne le faites pas, vous demandez simplement des problèmes sur toute la ligne. GET, PUTEt les DELETEméthodes sont nécessaires pour être idempotent. Imaginez ce qui se passerait dans votre application si le client récupérait chaque GETdemande possible pour votre service - si cela provoquait des effets secondaires visibles pour le client, alors quelque chose ne va pas.

Je suis d'accord que l'envoi d'un POSTavec une chaîne de requête mais sans corps semble étrange, mais je pense que cela peut être approprié dans certaines situations.

Considérez la partie requête d'une URL comme une commande à la ressource pour limiter la portée de la demande actuelle. En règle générale, les chaînes de requête sont utilisées pour trier ou filtrer une GETdemande (comme ?page=1&sort=title), mais je suppose qu'il est logique POSTde limiter également la portée (peut-être comme ?action=delete&id=5).

Don McCaughey
la source
4
J'ai choisi cette réponse pour ce cas particulier, mais je pense que l'argument de R. Bemrose est convaincant pour les API publiques.
Steven Huwig
4
Je ne pense pas que sa réponse soit strictement correcte. Si vous connaissez les paramètres d'URL pour votre publication de formulaire lorsque la page HTML est envoyée au client, vous pouvez appliquer ces paramètres d'URL à l'attribut d'action du formulaire, sinon JavaScript peut définir les paramètres d'URL lorsque le formulaire est soumis.
Don McCaughey
3
que diriez-vous d'une publication d'un fichier xml dans une URL avec des paramètres de requête? est-ce possible?
OpenCoderX
3
Un autre exemple: les données de la demande pourraient être dans l'entité http, tandis que le format demandé de la réponse est passé dans le paramètre de requête ( /action?response_format=json)
rds
4
+1 a appris quelque chose aujourd'hui. Supprimer a une technicité pour être idempotent. Si l'objet est réellement supprimé, vous obtiendrez un 404 introuvable, le serveur aura donc le même état mais la réponse sera différente. Voir l'image de la vache: restapitutorial.com/lessons/idempotency.html
JPK
131

Tout le monde a raison: restez avec POST pour les demandes non idempotentes.

Qu'en est-il de l'utilisation à la fois d'une chaîne de requête URI et d'un contenu de demande? Eh bien c'est HTTP valide (voir note 1), alors pourquoi pas?!

C'est aussi parfaitement logique: les URL, y compris leur partie chaîne de requête, servent à localiser les ressources. Alors que les verbes de méthode HTTP (POST - et son contenu de demande facultatif) servent à spécifier des actions, ou quoi faire avec des ressources. Ce devraient être des préoccupations orthogonales. (Mais, ce ne sont pas de belles préoccupations orthogonales pour le cas particulier de ContentType = application / x-www-form-urlencoded, voir la note 2 ci-dessous.)

Remarque 1: la spécification HTTP (1.1) n'indique pas que les paramètres de requête et le contenu s'excluent mutuellement pour un serveur HTTP qui accepte les requêtes POST ou PUT. Ainsi, tout serveur est libre d'accepter les deux. Autrement dit, si vous écrivez le serveur, rien ne vous empêche de choisir d'accepter les deux (sauf peut-être un cadre rigide). Généralement, le serveur peut interpréter les chaînes de requête selon les règles qu'il souhaite. Il peut même les interpréter avec une logique conditionnelle qui fait également référence à d'autres en-têtes comme Content-Type, ce qui conduit à la note 2:

Remarque 2: si un navigateur web est la façon dont les gens primaire accèdent à votre application web et application / x-www-form-urlencoded est le type de contenu qu'ils affichent, vous devez suivre les règles pour ce type de contenu. Et les règles d'application / x-www-form-urlencoded sont beaucoup plus spécifiques (et franchement inhabituelles): dans ce cas, vous devez interpréter l'URI comme un ensemble de paramètres et non comme un emplacement de ressource. [C'est le même point d'utilité soulevé par Powerlord; qu'il peut être difficile d'utiliser des formulaires Web pour publier du contenu sur votre serveur. Juste expliqué un peu différemment.]

Remarque 3: à quoi servent les chaînes de requête à l'origine? La RFC 3986 définit les chaînes de requête HTTP comme une partie URI qui fonctionne comme un moyen non hiérarchique de localiser une ressource.

Dans le cas où les lecteurs posant cette question souhaitent demander ce qu'est une bonne architecture RESTful: le modèle d'architecture RESTful ne nécessite pas que les schémas URI fonctionnent d'une manière spécifique. L'architecture RESTful se préoccupe des autres propriétés du système, comme la mise en cache des ressources, la conception des ressources elles-mêmes (leur comportement, leurs capacités et leurs représentations), et si l'idempotence est satisfaite. Ou en d'autres termes, réaliser une conception hautement compatible avec le protocole HTTP et son ensemble de verbes de méthode HTTP. :-) (En d'autres termes, l'architecture RESTful n'est pas très presciptive avec la façon dont les ressources sont localisées .)

Remarque finale: parfois, les paramètres de requête sont utilisés pour d'autres choses encore, qui ne sont ni la recherche de ressources ni l'encodage de contenu. Avez-vous déjà vu un paramètre de requête comme «PUT = true» ou «POST = true»? Il s'agit de solutions de contournement pour les navigateurs qui ne vous permettent pas d'utiliser les méthodes PUT et POST. Bien que ces paramètres soient considérés comme faisant partie de la chaîne de requête d'URL (sur le fil), je soutiens qu'ils ne font pas partie de la requête de l'URL dans l'esprit .

Tim Lovell-Smith
la source
66

Tu veux des raisons? En voici un:

Un formulaire Web ne peut pas être utilisé pour envoyer une demande à une page qui utilise un mélange de GET et POST. Si vous définissez la méthode du formulaire sur GET, tous les paramètres se trouvent dans la chaîne de requête. Si vous définissez la méthode du formulaire sur POST, tous les paramètres se trouvent dans le corps de la demande.

Source: norme HTML 4.01, section 17.13 Soumission de formulaire

Powerlord
la source
10
C'est un argument décent, mais je pense que les implémentations Javascript des navigateurs modernes en font un point discutable. J'y penserai cependant - c'est convaincant d'une manière à l'épreuve du temps. Ce n'est pas parce que je n'utilise pas de formulaire pour cela maintenant que je ne veux pas le faire plus tard.
Steven Huwig
9
Mélanger GET avec POST est juste une très mauvaise idée - briser terriblement HTTP et sans raison valable.
aehlke
6
Cet extrait n'apparaît pas sur la page à laquelle vous êtes lié
Gareth
40
Oui, mais l'attribut method définit simplement la manière dont le "jeu de données de formulaire" est inclus dans la demande. Lorsque le methodest POST, il n'est pas question de modifier l'URI dans le formulaire action. Et tout URI peut bien sûr déjà contenir une partie de chaîne de requête.
Gareth
16
@Powerlord C'est tout simplement faux. Essayez de configurer un formulaire pour POST avec une action par exemple. /Books?bookCode=1234. Le serveur Web recevra des variables de formulaire POST et une chaîne de requête.
Jez
9

D'un point de vue programmatique, pour le client, il empaquette les paramètres et les ajoute à l'url et effectue un POST par rapport à un GET. Côté serveur, il évalue les paramètres entrants de la chaîne de requête au lieu des octets publiés. Fondamentalement, c'est un lavage.

Il pourrait y avoir des avantages / inconvénients dans la façon dont des plates-formes clientes spécifiques fonctionnent avec les routines POST et GET dans leur pile réseau, ainsi que dans la façon dont le serveur Web traite ces demandes. Selon votre implémentation, une approche peut être plus efficace que l'autre. Savoir que cela guiderait votre décision ici.

Néanmoins, du point de vue d'un programmeur, je préfère autoriser soit un POST avec tous les paramètres dans le corps, soit un GET avec tous les paramètres sur l'URL, et ignorer explicitement les paramètres d'URL avec toute demande POST. Cela évite la confusion.

jro
la source
8

Je pense qu'il pourrait encore être assez reposant d'avoir des arguments de requête qui identifient la ressource sur l'URL tout en gardant la charge utile de contenu confinée au corps du POST. Cela semblerait séparer les considérations de "Qu'est-ce que j'envoie?" contre "À qui dois-je l'envoyer?".

swizzcheez
la source
5
La question ne concernait pas REST.
Steven Huwig
3
@ user359996 Toutes les API HTTP ne sont pas RESTful. En fait, la plupart des API qui prétendent que ce n'est pas le cas. De plus, fait amusant, REST n'est pas non plus uniquement HTTP.
Alec Mev
4

Le camp REST a quelques principes directeurs que nous pouvons utiliser pour normaliser la façon dont nous utilisons les verbes HTTP. Cela est utile lors de la construction des API RESTful comme vous le faites.

En un mot: GET devrait être en lecture seule, c'est-à-dire n'avoir aucun effet sur l'état du serveur. POST est utilisé pour créer une ressource sur le serveur. PUT est utilisé pour mettre à jour ou créer une ressource. DELETE est utilisé pour supprimer une ressource.

En d'autres termes, si votre action API modifie l'état du serveur, REST nous conseille d'utiliser POST / PUT / DELETE, mais pas GET.

Les agents utilisateurs comprennent généralement que faire plusieurs POST est mauvais et met en garde contre cela, car l'intention du POST est de modifier l'état du serveur (par exemple, payer les marchandises à la caisse), et vous ne voudrez probablement pas le faire deux fois!

Comparez avec un GET que vous pouvez faire souvent comme vous le souhaitez (idempotent).

saille
la source
13
Le camp REST dit que vous devez utiliser HTTP comme défini dans la spécification HTTP. ie RFC2616 Rien de plus, rien de moins.
Darrel Miller
1
@Darrel Référence ibm.com/developerworks/webservices/library/ws-restful : REST demande aux développeurs d'utiliser les méthodes HTTP de manière explicite et d'une manière cohérente avec la définition du protocole. Ce principe de conception REST de base établit un mappage un à un entre les opérations de création, de lecture, de mise à jour et de suppression (CRUD) et les méthodes HTTP. Selon ce mappage: Pour créer une ressource sur le serveur, utilisez POST. Pour récupérer une ressource, utilisez GET. Pour modifier l'état d'une ressource ou pour la mettre à jour, utilisez PUT. Pour supprimer ou supprimer une ressource, utilisez DELETE.
saille
5
Désolé mais c'est tout simplement faux. REST requiert la conformité à une interface uniforme. Si vous utilisez HTTP, cette interface uniforme est définie en partie par RFC 2616. Dans cette spécification, il n'y a pas de mappage un à un entre la création, la lecture, la mise à jour et la suppression et les méthodes HTTP.
Darrel Miller
3
GET et DELETE correspondent assez bien à Read et Delete dans CRUD, mais l'utilisation de PUT / POST pour Update et Create n'est pas aussi simple. Voir stackoverflow.com/questions/630453/put-vs-post-in-rest
dcstraw
5
En y repensant 6 ans plus tard, et étant donné que la question a été vue ~ 100 000 fois, je pense que cela vaut la peine de mettre une petite mise à jour. Darrel est correct selon la définition de Fielding de REST ( ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm ) - il n'y a aucune mention de mappage des verbes HTTP à CRUD. Les conseils des développeurs IBM (lien dans le commentaire ci-dessus) reflètent la pratique courante dans la mise en œuvre des API RESTful, et non la définition de Fielding de REST.
saille
-13

Je suis d'accord - il est probablement plus sûr d'utiliser une demande GET si vous passez simplement des données dans l'URL et non dans le corps. Voir cette question similaire pour quelques vues supplémentaires sur l'ensemble du concept POST + GET.

Marc Novakowski
la source
17
Si l'opération a des effets secondaires, il n'est certainement pas «plus sûr» d'utiliser la méthode GET car le navigateur suppose que tous les GET sont idempotents.
dcstraw
Les moteurs de recherche convertissent également cela en un cauchemar, car Google "cliquera" en toute sécurité sur tous les liens avec la demande GET, mais omettra tout le reste. Il n'est pas si sûr de quitter un service qu'un robot innocent peut accidentellement effacer la base de données.
Alejandro