HTTP hat ein neues Verb für die Suche
HTTP QUERY ermöglicht sichere, idempotente Suchanfragen mit Request-Body. Erfahren Sie, wie Caching und Wiederholungen funktionieren und welche Clients und Systeme den Einsatz unterstützen.
Die HTTP-Methode QUERY, im Juni 2026 in RFC 10008 definiert, überträgt die Abfrage wie POST im Request-Body, ist aber wie GET sicher (safe) und idempotent. Responses können daher gecacht und fehlgeschlagene Requests automatisch wiederholt werden.
Die meisten API-Teams kennen das Muster: Ein Such-Endpoint beginnt als aufgeräumter GET-Request und endet als URL, in die verschachtelte Filter, Datumsbereiche und Sortierschlüssel URL-kodiert sind. Irgendwann stellt jemand den Endpoint auf POST um, und danach funktionieren weder Caching noch Retries.
Dieser Artikel beschreibt das Problem, das QUERY löst, zeigt einen QUERY-Austausch auf Protokollebene und erläutert, welche Teile des Stacks die Methode bereits akzeptieren und welche sie noch ablehnen.
Das Wichtigste in Kürze
- QUERY ist eine sichere, idempotente HTTP-Methode, die ihre Abfrage im Request-Body überträgt. Sie ist in RFC 10008 (Juni 2026) standardisiert.
- Ein Server muss einen QUERY-Request ablehnen, dessen Content-Type fehlt oder nicht zum Body passt. Caches, die QUERY-Responses speichern, nehmen den Request-Body in den Cache-Key auf.
- Skripte können QUERY per
fetch()senden. Ein HTML-Formular mitmethod="query"fällt dagegen auf GET zurück und verwirft den Body. - Ein Cross-Origin-QUERY aus dem Browser löst immer einen CORS-Preflight aus, da QUERY keine CORS-safelisted Methode ist.
- Jeder Server, Proxy oder jede WAF, der oder die die Methode nicht kennt, kann den Request ablehnen, bevor er Ihre Anwendung erreicht.
Warum hängen Such-Endpoints zwischen GET und POST fest?
Für komplexe Suchen eignet sich weder GET noch POST wirklich. GET packt jeden Filter in die URL. POST verlagert die Filter in den Body, signalisiert aber jedem Intermediär, dass der Request den Zustand verändern könnte.
RFC 9110 verlangt, dass jeder Sender und Empfänger URIs mit mindestens 8.000 Oktetten verarbeiten kann. Das ist eine Untergrenze, keine Obergrenze. HTTP legt kein Maximum fest, sodass jeder Proxy, jedes Gateway und jeder Server auf dem Weg eine längere URL ablehnen kann. Lange Query-Strings landen außerdem im Browserverlauf, in Server-Logs und in Lesezeichen und legen damit offen, was die Filter enthalten.
POST vermeidet diese Probleme, ist aber weder sicher noch idempotent. Ein idempotenter Request hat dieselbe beabsichtigte Wirkung, egal ob er einmal oder zehnmal gesendet wird. RFC 9110 weist Clients an, einen nicht idempotenten Request nicht automatisch zu wiederholen, es sei denn, sie können auf andere Weise erkennen, dass er in der Praxis idempotent ist. Deshalb verwenden Caches POST-Responses in der Regel nicht wieder, und Gateways wiederholen keinen POST-Request, der mittendrin fehlschlägt.
Was ist die HTTP-Methode QUERY?
Gemäß RFC 10008 fordert ein QUERY-Request den Server auf, die im Request-Body beschriebene Abfrage auszuführen und das Ergebnis zurückzugeben, ohne auf dem Server etwas zu verändern. Ein Client oder Proxy kann einen QUERY-Request daher erneut senden oder neu starten, ohne befürchten zu müssen, dass ein abgebrochener erster Versuch den Zustand verändert hat. Bei POST ist diese Annahme nicht sicher. So sieht der Request auf Protokollebene aus (die einzelnen Bestandteile erläutert der Artikel zur Anatomie eines HTTP-Requests):
QUERY /products/search HTTP/1.1
Host: api.example.com
Content-Type: application/json
Accept: application/json
{"category": "laptops", "price": {"max": 1500}, "brands": ["acme", "globex"], "sort": "price_asc"}
Die Abfrage wird durch den Body zusammen mit seinem Media Type definiert. Fehlt der Content-Type-Header oder passt er nicht zum Inhalt des Bodys, muss der Server den Request laut RFC 10008 ablehnen. Die Statuscode-Empfehlungen in RFC 10008 nennen einen 4xx-Code, etwa 400, wenn kein Media Type angegeben ist, und 415, wenn die Ressource den gesendeten Media Type nicht unterstützt.
Eine Response könnte so aussehen:
HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: max-age=60
Accept-Query: application/json
Content-Location: /products/search/results/7f3a
Location: /products/search/queries/7f3a
{"results": [ ... ]}
Jeder Header erfüllt eine bestimmte Aufgabe:
- Cache-Key: QUERY-Responses sind cachebar. Ein Cache, der sie speichert, nimmt den Request-Body in den Cache-Key auf, denn zwei QUERY-Requests an dieselbe URL mit unterschiedlichen Bodys stellen unterschiedliche Fragen.
Accept-Query: Mit diesem Response-Header listet ein Server die Abfrageformate auf, die er akzeptiert, notiert als Structured-Field-Liste von Media Types. Ein Wert gilt für alle URIs auf dem Server mit demselben Pfad, unabhängig vom Query-String.- Content-Location und Location: In einer QUERY-Response identifiziert Content-Location das Ergebnis genau dieser Abfrage. Location liefert eine URI für die Abfrage selbst, die ein Client später per einfachem GET abrufen kann. Wie sich diese Header normalerweise verhalten, beschreibt der Artikel Was steckt in einer HTTP-Response?.
Cache-Control ist im Beispiel eine gewöhnliche Caching-Konfiguration. RFC 10008 schreibt sie nicht vor.
Wo funktioniert QUERY heute?
Die HTTP-Methode QUERY funktioniert bereits in mehreren Server-Runtimes, Frameworks und HTTP-Clients, sofern keine Komponente zwischen Client und Server sie ablehnt.
- Node.js akzeptiert QUERY im Modul http. Der mitgelieferte Parser llhttp definiert
HTTP_QUERY(siehe Nodes Kopie vonllhttp.h) und erkennt die Methode seit llhttp 9.2. Laut Node.js-Changelog wurde diese Parser-Version mit v21.7.2 ausgeliefert. Sie ist außerdem in v22 und höher sowie in v20.19.2 enthalten. In diesen Versionen enthälthttp.METHODSden Eintrag'QUERY', und ein Server-Handler siehtreq.method === 'QUERY'. - Der HTTP-Client von Go akzeptiert in
http.NewRequestjedes gültige Method-Token als Methodenstring und kann QUERY daher bereits senden:
package main
import (
"log"
"net/http"
"strings"
)
func main() {
body := strings.NewReader(`{"category":"laptops","price":{"max":1500}}`)
req, err := http.NewRequest("QUERY", "https://api.example.com/products/search", body)
if err != nil {
log.Fatal(err)
}
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()
}
- Laravel: Laravel 13.19.0 ergänzt eine Client-Methode
Http::query()sowie die Test-Helperquery()/queryJson()für das QUERY-Verb. Routen können QUERY überRoute::match()entgegennehmen. Die Test-Helper kamen mit laravel/framework PR #60662 hinzu. Ein eigener HelperRoute::query()wurde in den master-Branch von Laravel gemergt und nicht in 13.x, daher enthält kein 13.x-Release diesen Helper.
Im Browser kann fetch() QUERY per Skript an denselben Origin senden. Das Fetch-Issue zu QUERY (whatwg/fetch#1938) weist darauf hin, dass der Fetch Standard QUERY weder verbietet noch die Groß-/Kleinschreibung normalisiert. Browser senden den Methodenstring genau so, wie Sie ihn schreiben. Verwenden Sie daher immer Großbuchstaben:
const res = await fetch('/products/search', {
method: 'QUERY',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ category: 'laptops', price: { max: 1500 } }),
});
const data = await res.json();
Was unterstützt QUERY noch nicht?
Drei Dinge bremsen die HTTP-Methode QUERY derzeit aus: HTML-Formulare können sie nicht senden, manche Server und Sicherheitsschichten lehnen die Methode grundsätzlich ab, und Cross-Origin-Aufrufe erfordern einen Preflight.
Formulare. Skripte können QUERY per fetch() senden, Formulare nicht. Der Vorschlag zur Unterstützung von method="query" ist WHATWG HTML Issue #12594. Es ist weiterhin offen und mit „needs implementer interest“ gekennzeichnet. Bis es umgesetzt ist, kommt dieses Markup:
<form method="query" action="/products/search">
<input name="category" value="laptops">
<button>Search</button>
</form>
beim Server als GET ohne Body an, weil Browser eine unbekannte Formularmethode als GET behandeln. Eine für das Issue erstellte Live-Reproduktion demonstriert dieses Verhalten.
Server, Gateways und WAFs. Jeder Hop, der die Methode nicht kennt, kann sie ablehnen. Laut derselben Reproduktion beantwortet beispielsweise LiteSpeed einen QUERY-Request mit 400, bevor die Anwendung überhaupt ausgeführt wird. Reverse Proxies, Load Balancer, CDNs, API-Gateways und Firewalls müssen jeweils einzeln geprüft werden.
Cross-Origin-Preflight. QUERY steht nicht auf der Liste der CORS-safelisted Methods des Fetch Standards. Ein Cross-Origin-QUERY löst daher immer einen Preflight aus, unabhängig von den mitgesendeten Headern:
OPTIONS /products/search HTTP/1.1
Origin: https://app.example.com
Access-Control-Request-Method: QUERY
Access-Control-Request-Headers: content-type
HTTP/1.1 204 No Content
Access-Control-Allow-Origin: https://app.example.com
Access-Control-Allow-Methods: GET, POST, QUERY
Access-Control-Allow-Headers: content-type
Ist QUERY nicht in Access-Control-Allow-Methods aufgeführt, blockiert der Browser den eigentlichen Request.
| Umgebung | Status |
|---|---|
fetch(), Same Origin | Funktioniert |
fetch(), Cross Origin | Funktioniert nach einem Preflight, der QUERY erlaubt |
| HTML-Formulare | Fallback auf GET, Body wird verworfen |
| Node.js http | Funktioniert (v20.19.2+, v21.7.2+, v22+; llhttp 9.2 erkennt QUERY) |
| Go-HTTP-Client | Funktioniert (benutzerdefinierter Methodenstring) |
| Laravel 13.19+ | Funktioniert (Client, Tests, Route::match) |
| LiteSpeed | Mit 400 abgelehnt, bevor die App ausgeführt wird (dokumentiert in der Reproduktion zu #12594) |
| Proxies, CDNs, Gateways, WAFs | Abhängig von Produkt und Konfiguration |
Sollte GraphQL QUERY verwenden?
QUERY eignet sich für GraphQL-Query-Operationen, die ausschließlich Daten lesen und damit zu einer sicheren, idempotenten Methode mit Body passen. Mutations verändern den Zustand und gehören daher weiterhin zu POST. Wenn Sie die beiden API-Stile gegeneinander abwägen, finden Sie die Vor- und Nachteile im Erklärartikel GraphQL vs. REST. Das Argument für QUERY ist in beiden Fällen dasselbe: Suchartige Lesezugriffe erhalten Caching und Retries auf HTTP-Ebene zurück.
Was passieren muss, bevor QUERY durchgängig funktioniert
Damit QUERY überall funktioniert, muss jede Schicht zwischen dem Nutzer und Ihrem Handler die Methode kennen:
- Die HTML-Spezifikation muss
method="query"zulassen, und die Browser müssen es implementieren. - Jeder Hop (Origin-Server, Reverse Proxy, Load Balancer, CDN, API-Gateway und WAF) muss die Methode parsen und weiterleiten.
- Frameworks müssen QUERY an Handler routen und den Body parsen.
- Caches müssen Request-Body und Content-Type in den Cache-Key aufnehmen, bevor sie QUERY-Responses speichern.
Der CORS-Preflight ist so gewollt: RFC 10008 sieht ihn vor, und whatwg/fetch#1938 fordert keine Änderung der Safelist. Offen ist dort noch, ob der URL-basierte HTTP-Cache von Fetch ein Body-basiertes Caching für QUERY unterstützen soll.
Fazit
QUERY behebt eine seit Langem bestehende Diskrepanz in HTTP: Suchanfragen können einen Body mitführen, ohne auf Caching und sichere Retries zu verzichten. Skripte, Go-Clients und Laravel-Apps können die Methode schon heute nutzen. Formulare können es nicht, und Infrastruktur, die die Methode nicht kennt, lehnt sie womöglich weiterhin ab. Bevor Sie einen Endpoint umstellen, schicken Sie einen echten QUERY-Request durch Ihren vollständigen Produktionspfad inklusive CDN, Gateway und WAF, und lassen Sie den POST-Endpoint so lange weiterlaufen, bis jeder Hop die Methode durchreicht.
FAQs
Warum nicht einfach einen Request-Body mit GET senden, statt QUERY zu verwenden?
Ein GET-Body ist unzuverlässig. Laut RFC 9110, Abschnitt 9.3.1, hat ein Body bei GET keine allgemein definierte Bedeutung und kann weder das Ziel noch die Bedeutung des Requests ändern. Manche Server lehnen solche Requests grundsätzlich ab, weil sich ein GET-Body für Request Smuggling missbrauchen lässt. Zudem ist der Body nicht Teil des Standard-Cache-Keys. Bei QUERY ist der Body die Abfrage selbst und fließt in den Cache-Key ein.
Worin unterscheidet sich die Methode QUERY von der WebDAV-Methode SEARCH?
SEARCH ist eine WebDAV-Methode, 2008 in RFC 5323 definiert, zum Durchsuchen von DAV-Ressourcen mit XML-Abfragegrammatiken. QUERY ist eine universelle HTTP-Methode für beliebige Abfrageformate. Beide Methoden sind sicher, aber SEARCH hat sich nie über WebDAV hinaus verbreitet. Frühe Entwürfe der QUERY-Spezifikation verwendeten noch den Namen SEARCH. Die Autoren wechselten zu QUERY, weil SEARCH und die übrigen bestehenden sicheren Methoden aus WebDAV stammen und auf einem generischen XML-Media-Type beruhen, und weil der Name QUERY dem Query-Teil einer URI entspricht.
Kann ich QUERY-Endpoints in OpenAPI dokumentieren?
Ja, ab OpenAPI 3.2.0, veröffentlicht im September 2025. Diese Version bringt integrierte Unterstützung für die Methode query mit, sodass eine QUERY-Operation genau wie get oder post ein requestBody-Schema und Responses deklarieren kann. Andere nicht standardisierte Methoden gehören in die neue Map additionalOperations. OpenAPI 3.0 und 3.1 bieten kein Feld für QUERY, und die Tooling-Unterstützung für 3.2 variiert von Generator zu Generator.
Welchen Statuscode gibt ein Server zurück, wenn er QUERY nicht unterstützt?
Laut RFC 9110 sollte ein Server, der eine Request-Methode nicht kennt, mit 501 Not Implemented antworten. Ein Server, der QUERY kennt, die Methode aber für eine bestimmte Ressource nicht zulässt, gibt 405 Method Not Allowed zurück, zusammen mit einem Allow-Header, der die unterstützten Methoden auflistet. Proxies und WAFs können anders fehlschlagen, etwa mit einem einfachen 400. Eine Fallback-Logik auf POST sollte daher alle drei Fälle abdecken.