Catégorie de l'article : Technique

Méthode HTTP QUERY : le verbe qui règle enfin le duel GET contre POST

·
lecture 6 minutes
Frédéric Pineau - Expert Web Performance
publié par

Frédéric Pineau
Directeur Technique

On a tous écrit ce genre d’URL un jour : ?colors=Bleu &colors=Vert &clothingSizes=FR+38 &clothingSizes=FR+40 &minPrice=16224 &maxPrice=59945 &brands=Nike &brands=Adidas &inStock=true&onSale=false &rating=4 &category=chaussures &subcategory=running &sort=price_asc &page=1&limit=24. Ça marche, mais c’est moche, ça touche vite la limite de caractères de certains proxys, et dès que le nombre de filtres grimpe on finit par transformer une route de listing en POST. Sauf que POST n’est pas fait pour ça : sa définition, c’est de soumettre une entité et de provoquer un changement d’état côté serveur. On détourne le verbe pour des raisons de confort, pas de sémantique.

Depuis le 15 juin 2026, il existe une réponse officielle à ce problème : la RFC 10008, qui fait passer la méthode HTTP QUERY en statut Proposed Standard, après plus de dix ans en brouillon à l’IETF. J’ai voulu creuser les deux points essentiels face à cette nouvelle feature : en quoi c’est réellement plus performant, et surtout, est-ce qu’on peut s’en servir aujourd’hui.

GET, POST, QUERY : une histoire à la Sergio Leone

Il y a un truc presque cinématographique dans ce trio de verbes, et ça m’a fait penser au Bon, la Brute et le Truand.

  • GET, c’est le Bon. Propre, prévisible, cachable, il respecte les règles du jeu HTTP à la lettre. Le souci, c’est qu’il ne peut porter ses paramètres que dans l’URL, et qu’une URL a des limites, en taille comme en lisibilité. Le Bon est honnête mais un poil rigide.
  • POST, c’est la Brute. Il fait le boulot, il porte un body aussi gros qu’on veut, mais il le fait à la hache : par nature, un POST n’est ni sûr ni cachable, puisqu’il est censé modifier quelque chose côté serveur. L’utiliser pour une simple recherche, c’est mentir aux proxys, aux CDN et à tous les outils qui font confiance à la sémantique HTTP.
  • QUERY, c’est le Truand. Malin, il pioche dans les deux répertoires : la capacité de POST à transporter un body JSON complexe, et les garanties de GET (sûr, idempotent, cachable). Il ne triche pas vraiment, il joue juste plus finement que les deux autres avec les règles existantes. Et comme Tuco, il finit par tirer son épingle du jeu là où les débats sémantiques s’éternisaient depuis des années.

Comment fonctionne la méthode HTTP QUERY concrètement

La syntaxe est proche de POST : les critères de filtrage vont dans le body, pas dans l’URL, et le Content-Type devient obligatoire (la RFC impose de rejeter la requête s’il est absent ou incohérent avec le body).

curl -i -X QUERY https://api.example.com/orders \
  -H "Content-Type: application/json" \
  -d '{"filter":{"status":["paid","refunded"],"createdAt":{"gte":"2026-01-01"}},"sort":[{"field":"createdAt","direction":"desc"}],"limit":100}'

Plus besoin de rallonger l’URL, le filtre complexe tient dans un JSON structuré, lisible, et sans limite pratique de taille. Un serveur peut aussi annoncer les formats de requête qu’il accepte via l’en-tête Accept-Query (JSONPath, SQL, un DSL maison), et une réponse peut inclure Location ou Content-Location pour donner une URI réutilisable en GET sur cette même requête ou sur son résultat, un moyen de retrouver, plus tard, un comportement de partage d’URL proche de celui de GET.

En quoi QUERY est plus performant

La différence de fond avec POST, c’est que QUERY est déclaré comme méthode sûre et idempotente dans la RFC, donc rejouable sans risque après un échec de connexion, et cachable par les intermédiaires HTTP (CDN, proxy, reverse-proxy) au même titre qu’un GET. Avec POST, ce n’est pas le cas par défaut : il faut bricoler sa propre couche de cache applicative.

Le point technique à retenir, c’est que la clé de cache ne peut plus être seulement l’URL : elle doit intégrer le body de la requête et ses métadonnées (typiquement une URI plus un hash du body JSON normalisé, clés triées). Deux requêtes QUERY sur la même URL mais avec des filtres différents doivent aboutir à deux entrées de cache distinctes, sinon on sert la réponse d’une recherche à la place d’une autre. C’est plus subtil à implémenter qu’un cache GET classique, mais ça déplace un problème qu’on gérait auparavant à la main, en Redis ou en cache applicatif, vers l’infrastructure HTTP standard.

Sur une API avec beaucoup de trafic de recherche ou de reporting, ça change vraiment la donne côté charge serveur et côté latence perçue, un sujet qu’on suit de près côté web performance. C’est typiquement le genre de chose que MilleCheck regarde du côté cache HTTP et en-têtes de réponse : un GET détourné en POST perd sa cachabilité, et ça se voit sur les temps de réponse mesurés, un peu comme le poids d’un JavaScript bloated peut plomber un site en silence.

Où en est vraiment le support aujourd’hui

C’est le point le plus important à retenir avant de se lancer : QUERY est standardisé côté protocole, mais l’écosystème est encore très inégal, mi-2026.

Côté serveur, ça avance vite : Node.js parse QUERY nativement depuis les versions 21.7.2 et 22+, Fastify le supporte via addHttpMethod, Symfony l’a intégré dès sa version 7.4 (HttpFoundation gère le body QUERY comme un POST), et nginx a une prise en charge basique en amont. Rails a une proposition active en discussion, et ASP.NET Core le reconnaît dans les previews de .NET 11. OpenAPI 3.2 modélise déjà les opérations QUERY.

Côté frameworks plus lourds, c’est plus lent : chez Spring, la pull request est ouverte mais RequestMethod n’inclut toujours pas QUERY début juillet 2026, donc impossible de router dessus avec @RequestMapping pour l’instant. Laravel a une PR en cours pour ajouter Http::query() côté client HTTP.

Côté navigateurs, c’est là que ça coince le plus. fetch() et XHR peuvent techniquement envoyer QUERY (la méthode n’est ni interdite ni normalisée par le navigateur), mais ni Chrome ni Firefox ne mettent en cache les réponses QUERY à ce jour. Un formulaire HTML déclaratif (<form method="query">) retombe simplement sur GET et perd le body. QUERY n’est pas non plus une méthode « CORS-safelisted », donc toute requête cross-origin déclenchera systématiquement un preflight. Et MDN ne documente pas encore la méthode.

Bilan honnête : en 2026, QUERY est surtout une histoire serveur-à-serveur et de gateway d’API, exactement là où vit le trafic de recherche et de reporting interne. Pour du client web classique dans le navigateur, c’est encore prématuré.

Ce que j’en retiens

Si vous avez une API avec des routes de recherche complexes, côté backend ou entre microservices, il n’y a plus vraiment de raison d’attendre pour tester QUERY, surtout si vous êtes déjà sur Symfony ou Node. Pour du grand public dans un navigateur, en revanche, mieux vaut patienter que le support de fetch() et la mise en cache navigateur suivent. On garde un œil sur le ticket whatwg/fetch #1938, c’est probablement là que ça se jouera en premier.

Sources : lilting.ch, HTTP QUERY method (RFC 10008) vs POST /search: cache keys and CORS preflightissue spring-framework #36988
Visuel généré à partir d’une intelligence artificielle.

Articles similaires