RFC 10008: Die neue HTTP-Methode QUERY
(rfc-editor.org)- RFC 10008 definiert die HTTP-Methode QUERY, bei der die Zielressource eine im Request-Body enthaltene Anfrage sicher und idempotent verarbeitet und anschließend das Ergebnis zurückgibt
- QUERY kombiniert den safe/idempotent-Charakter von GET mit der Body-Übertragung von POST und verringert so Probleme mit langen URIs, URI-Encoding-Kosten, Offenlegung in Logs und dem Aufwand, jede Anfragekombination als eigene Ressource zu behandeln
- Ein Server kann einen QUERY-Request nur verarbeiten, wenn Content-Type und Body konsistent sind; nicht unterstützte Typen, inkonsistente Bodies und inhaltlich nicht verarbeitbare Anfragen können jeweils mit unterschiedlichen 4xx-Antworten unterschieden werden
- Eine erfolgreiche Antwort kann mit Content-Location eine Ergebnisressource der Anfrage und mit Location eine equivalent resource angeben, über die sich dieselbe Anfrage erneut ausführen lässt
- QUERY-Antworten sind cachebar, aber der Cache-Schlüssel muss auch Body und Metadaten umfassen; in CORS-Umgebungen ist wegen fehlender Einstufung als safelisted method ein preflight erforderlich
HTTP-Anfragemuster, die QUERY lösen soll
- RFC 10008 ist ein Internet-Standards-Track-Dokument, das die HTTP-Request-Methode QUERY definiert
- QUERY fordert die Zielressource auf, den Request-Body zu verarbeiten und das Ergebnis in der Antwort zurückzugeben
- Wie POST verwendet QUERY einen Body, ist aber als safe und idempotent definiert, sodass automatische Wiederholungen oder Neustarts möglich sind
- Bestehende GET-Anfragen übergeben Eingaben üblicherweise in der URI
GET /feed?q=foo&limit=10&sort=-published HTTP/1.1
- Wenn Anfragedaten in die URI gelegt werden, steigen die Einschränkungen mit der Datenmenge
- Da mehrere unabhängige Systeme beteiligt sein können, ist die tatsächliche URI-Größenbeschränkung im Voraus oft schwer abzuschätzen
- HTTP empfiehlt, dass Sender und Empfänger mindestens 8000 octets unterstützen, garantiert dies aber nicht für alle Systeme auf dem Übertragungsweg
- Manche Daten lassen sich nur mit hohem Aufwand in eine gültige URI encodieren
- Request-URIs landen eher in Logs oder Bookmarks als Request-Bodies
- Werden Anfragen direkt in die URI encodiert, wird jede mögliche Eingabekombination als separate Ressource behandelt
Eine Methode, die die Semantik zwischen GET und POST klarer macht
- Viele Implementierungen übertragen Anfragen nicht per GET, sondern im POST-Body
POST /feedContent-Type: application/x-www-form-urlencoded- Body:
q=foo&limit=10&sort=-published
- Ohne Wissen über die konkrete Ressource und den Server ist dabei nicht erkennbar, ob es sich um eine sichere und idempotente Anfrage handelt
- QUERY sendet dieselben Eingaben im Request-Body, ist aber bereits auf Methodenebene sicher und idempotent
QUERY /feedContent-Type: application/x-www-form-urlencoded- Body:
q=foo&limit=10&sort=-published
- Diese explizite Semantik erleichtert es, HTTP-Funktionen wie Caching und automatische Retries anzuwenden
- Der Server kann der Anfrage selbst oder einem bestimmten Anfrageergebnis eine URI zuweisen, die später per GET genutzt werden kann
Zentrale Regeln der QUERY-Methode
- QUERY wird verwendet, um serverseitige Anfragen zu starten
- GET fordert eine Repräsentation der durch die Ziel-URI identifizierten Ressource an, während QUERY die Ausführung einer Anfrageoperation innerhalb des Geltungsbereichs der Zielressource verlangt
- Request-Body und Medientyp definieren die Anfrage, und der origin server legt den Operationsbereich relativ zur Zielressource fest
- Der Server muss den Request fehlschlagen lassen, wenn das Request-Feld Content-Type fehlt oder nicht zum Request-Body passt
- Der query part der Ziel-URI beteiligt sich wie bei allen HTTP-Methoden an der Identifikation der Zielressource
- Ob und wie dieser query part das Ergebnis direkt beeinflusst, ist ressourcenspezifisches Verhalten und liegt außerhalb dieser Spezifikation
- QUERY ist aus Sicht der Zielressource safe
- Der Client fordert keine Änderung des Zustands der Zielressource an und erwartet sie auch nicht
- Dass der Server HTTP-Ressourcen anlegt, über die zusätzliche Informationen abgerufen werden können, ist nicht verboten
- QUERY ist idempotent und kann daher nach Verbindungsfehlern bei Bedarf erneut gesendet oder wiederholt werden
- Eine Antwort mit
200 OKzeigt an, dass die Anfrage erfolgreich verarbeitet wurde und das Ergebnis im Response-Body enthalten ist
Medientypen, Aushandlung und Fehlerbehandlung
- Die Bedeutung eines QUERY-Requests hängt vom Request-Body und zugehörigen Metadaten wie dem Medientyp ab
- Requests, bei denen Body und Metadaten nicht konsistent sind, sollten in der Regel mit einem 4xx Client Error abgelehnt werden
- Die Fehlerbehandlung hängt davon ab, an welcher Stelle der Request fehlerhaft ist
- Fehlt die Medientyp-Information, ist der Request definitionsgemäß fehlerhaft und sollte mit einem 4xx-Statuscode wie
400fehlschlagen - Ist ein Medientyp angegeben, wird aber von der Ressource nicht unterstützt, ist
415 Unsupported Media Typepassend - Auch wenn der Medientyp grundsätzlich bekannt ist, aber für die QUERY-Semantik der Zielressource keine Bedeutung hat, ist
415angemessen - Wenn der Medientyp nicht zum tatsächlichen Request-Body passt, kann
400 Bad Requestzurückgegeben werden - Der Server darf kein content sniffing betreiben, um anhand des Bodys einen fehlenden oder falschen Wert zu erraten und zu überschreiben
- Stimmen Typ und Body überein, ist die konkrete Anfrage aber inhaltlich nicht verarbeitbar, kann
422 Unprocessable Contentverwendet werden - Ein Beispiel für
422ist eine syntaktisch korrekte SQL-Anfrage, die auf eine nicht existierende Tabelle verweist - Wenn die vom Client per
Acceptangeforderten Response-Medientypen von der Ressource nicht unterstützt werden, ist406 Not Acceptablepassend
- Fehlt die Medientyp-Information, ist der Request definitionsgemäß fehlerhaft und sollte mit einem 4xx-Statuscode wie
- Das Response-Feld
Accept-Querykann dem Client mitteilen, welche Anfragemedientypen unterstützt werden
equivalent resource, Content-Location, Location
- Eine equivalent resource ist eine Ressource, die einen bestimmten QUERY-Request und dessen Ziel repräsentiert und auf GET-Requests antwortet
- Eine equivalent resource berücksichtigt sowohl den Request-Body als auch die Metadaten
- Dazu gehören Repräsentationsmetadaten wie der Medientyp des Bodys
- Der Server kann einer equivalent resource eine URI zuweisen, ist dazu aber nicht verpflichtet
- Eine erfolgreiche Antwort kann im Header Content-Location einen Ressourcenbezeichner für das Anfrageergebnis enthalten
- Der Client kann ein GET an die angegebene URI senden, um das Ergebnis der gerade ausgeführten Anfrageoperation abzurufen
- Diese Ressource kann temporär sein
- Eine erfolgreiche Antwort kann im Header Location die URI der equivalent resource des QUERY-Requests enthalten
- Der Client kann dann ohne erneutes Senden des Anfrage-Bodys ein GET an die angegebene URI senden und dieselbe Anfrageoperation wiederholen
- Auch diese URI kann temporär sein
- Falls eine spätere Anfrage fehlschlägt, kann der Client es mit dem ursprünglichen QUERY-Ziel und dem zuvor gesendeten Body erneut versuchen
Weiterleitungen und bedingte Requests
- Der Server kann auf einen QUERY-Request mit einer indirekten Antwort reagieren, die den User Agent auf eine andere URI umleitet
301 Moved Permanentlyund308 Permanent Redirectzeigen an, dass die Zielressource dauerhaft an eine andere durch Location angegebene URI verschoben wurde302 Foundund307 Temporary Redirectbedeuten eine temporäre Verschiebung der Zielressource- In allen vier Fällen schlägt der Server vor, dass der ursprüngliche Request durch Senden eines entsprechenden QUERY-Requests an die neue Ziel-URI ausgeführt werden kann
- Die Ausnahme, nach
301oder302einen POST in GET umzuwandeln, gilt nicht für QUERY-Requests 303 See Otherfür QUERY zeigt an, dass die ursprüngliche Anfrage als normaler Abrufrequest an die in Location angegebene URI ausgeführt werden kann- In HTTP wird dabei ein GET-Request an die neue Ziel-URI gesendet
- Bei bedingten QUERY-Requests ist die selected representation dieselbe wie bei einem GET auf die equivalent resource dieses QUERY-Requests
- Der Client kann verlangen, dass ein Anfrageergebnis nur dann in der Antwort zurückgegeben wird, wenn die durch bedingte Header angegebenen Bedingungen erfüllt sind
Caching und Range-Requests
- Antworten auf die QUERY-Methode sind cachebar, und der Cache kann verwendet werden, um spätere QUERY-Requests zu erfüllen
- Der Cache-Schlüssel eines QUERY-Requests muss den Request-Body und zugehörige Metadaten umfassen
- Der Cache darf Unterschiede entfernen, die für die Semantik des Cache-Schlüssels nicht relevant sind
- Entfernen von content encoding
- Normalisierung entsprechend Formatkonventionen, die durch einen Mediensubtyp-Suffix wie
+jsonangezeigt werden - Normalisierung entsprechend der durch
Content-Typebeschriebenen Body-Semantik
- Diese Transformationen dienen ausschließlich der Erzeugung des Cache-Schlüssels und verändern den Request selbst nicht
- Mit der Cache-Direktive
no-transformkann der Client angeben, dass solche Transformationen unerwünscht sind, diese Direktive ist jedoch advisory - Das Caching von QUERY-Antworten ist inhärent komplexer als bei GET
- Um den Cache-Schlüssel zu bestimmen, muss der gesamte Request-Body gelesen werden
- Wenn eine QUERY-Antwort per Location eine URI für eine equivalent resource liefert, kann der Client anschließend auf GET umsteigen und die Verarbeitung vereinfachen
- Die Semantik von Range Request bei QUERY ist dieselbe wie bei GET
- Die zum Zeitpunkt der Spezifikation einzige definierte range unit, Byte Range Request, ist für QUERY-Ergebnisse von geringem Nutzen
- Häufig bietet bereits das Anfrageformat selbst eine Begrenzung oder Paginierung des Ergebnisses, etwa wie
FETCH FIRST ... ROWS ONLYin SQL; die Nutzung solcher eingebauten Funktionen wird erwartet
Response-Header Accept-Query
- Der Response-Header Accept-Query zeigt direkt an, dass eine Ressource die QUERY-Methode unterstützt, und identifiziert die nutzbaren Medientypen für Anfragen
- Accept-Query ist eine Liste von media ranges unter Verwendung der Structured-Fields-Syntax
- Eine media range wird als List Structured Header Field aus Tokens oder Strings mit media-range-Werten ohne Parameter dargestellt
- Medientyp-Parameter werden auf Structured Field Parameters abgebildet
- Die Wahl zwischen String und Token ist semantisch nicht wichtig
- Ein Empfänger darf Tokens in Strings umwandeln, darf sie aber nicht je nach empfangenem Typ unterschiedlich behandeln
- Medientypen lassen sich nicht exakt auf Token abbilden; wenn führende Ziffern erlaubt sein müssen, ist die String-Form zu verwenden
- Unterstützte Wildcards sind nur
*/*oderxxxx/* - Die Reihenfolge der im Feldwert aufgelisteten Typen ist nicht wichtig
- Der Accept-Query-Wert gilt für alle URIs eines Servers mit demselben path; die query component wird ignoriert
- Wenn Requests an dieselbe Ressource unterschiedliche Accept-Query-Werte zurückgeben, wird der zuletzt empfangene frische Wert verwendet
- Ein Beispiel lautet wie folgt
Accept-Query: "application/jsonpath", application/sql;charset="UTF-8"
- Accept-Query wirkt ähnlich wie
Accept, ist aber ein Structured Field und muss daher nach den Structured-Fields-Regeln aus RFC 9651 verarbeitet werden
Sicherheitsaspekte und CORS
- QUERY folgt allen allgemeinen Sicherheitsaspekten für HTTP-Methoden, wie sie in RFC 9110 definiert sind
- QUERY kann als Alternative dazu verwendet werden, Request-Informationen in der URI query component unterzubringen
- Da URIs eher protokolliert oder von Intermediären verarbeitet werden als Request-Bodies, kann QUERY bei sensiblen Informationen in Anfragen gegenüber GET vorteilhaft sein
- Wenn ein Server eine temporäre Ressource erstellt, die ein QUERY-Ergebnis repräsentiert, und ihr eine URI zuweist, darf diese URI keine sensiblen Teile enthalten, falls der ursprüngliche Request-Body Informationen enthielt, die nicht in Logs erscheinen sollten
- Wenn ein Cache QUERY-Bodies falsch normalisiert oder deutlich anders normalisiert als die Ressource selbst, kann er durch false positives falsche Antworten zurückgeben
- QUERY-Requests von User Agents mit CORS-Implementierung erfordern einen preflight-Request
- QUERY gehört nicht zur Menge der CORS-safelisted methods
IANA-Registrierung und Wahl des Methodennamens
- IANA fügt die Methode QUERY dem HTTP Method Registry hinzu
- Method Name:
QUERY - Safe:
yes - Idempotent:
yes - Specification: RFC 10008 Section 2
- Method Name:
- IANA fügt das Feld Accept-Query dem HTTP Field Name Registry hinzu
- Field Name:
Accept-Query - Status:
permanent - Structured Type:
List
- Field Name:
- Im HTTP Method Registry gab es bereits
PROPFIND,REPORTundSEARCHmit den Eigenschaften safe und idempotent - In frühen Phasen wurde
SEARCHverwendet, der endgültige Methodenname wurde jedoch QUERY - QUERY wurde aus folgenden Gründen gewählt
- Die Alternativen verwendeten im Request-Body den allgemeinen Medientyp
application/xml, und die Request-Semantik hing vollständig vom Body ab - Die Alternativen entstammten sämtlich dem WebDAV-Umfeld
QUERYerfasst die Beziehung zur query component der URI besonders gut
- Die Alternativen verwendeten im Request-Body den allgemeinen Medientyp
1 Kommentare
Hacker-News-Kommentare
Mit einem starken Motivationsbeispiel wäre das überzeugender gewesen, aber stattdessen wurde ein Beispiel gewählt, das sich zu leicht als GET ausdrücken lässt, was eher ablenkt
Selbst wenn man sich QUERY mit großen JSON-Filterstrukturen oder Bildeingaben im Request-Body vorstellt, fühlt es sich sehr seltsam an, dass der Request-Body Teil des Cache-Schlüssels wird. Damit entstehen unbegrenzt viele, nutzerkontrollierte Cache-Schlüssel, und übliche Caching-Strategien laufen praktisch darauf hinaus, den Request-Body bitweise zu vergleichen oder zu hashen, wodurch Cache-Invalidierung in böswilligen Szenarien sehr leicht wird
Wenn man einen Dienst baut, der komplexe Filterung oder komplexe Eingaben wie Bilder braucht, liegt das Caching wahrscheinlich weit entfernt von der HTTP-Ebene. Der Schlüssel würde sich dann etwa an einzelnen Datenspalten eines Joins orientieren oder an Embeddings, die über einen Perzeptions-Hash der dekodierten Bildeingabe indiziert werden, also nicht an der exakten Bitdarstellung auf dem Draht
Ich verstehe nicht, warum man so etwas unbedingt auf generische Weise abbilden will. Stattdessen wäre es viel besser, die Caching-Semantik bei POST mit einem neuen Header wie
"Vary: request-body"auszudrücken. Das wäre vollständig abwärtskompatibel und könnte außer für die 0,1 % der CDN-Anwendungsfälle, in denen dieses Verhalten vielleicht nützlich ist, einfach ignoriert werdenMir fällt kein Angriff auf Caching ein, der nicht genauso auch auf Query-Parameter anwendbar wäre. Wenn man den Cache fluten will, ist es genauso einfach, einen eindeutigen Query-Parameter mit 30 Zeichen zu erzeugen wie einen 30-MB-Request-Body
Realistisch betrachtet würden Systeme für das öffentliche Internet einen kryptographischen Hash als Cache-Schlüssel verwenden, damit dieser immer gleich groß ist. Cache-Schlüssel enthalten ohnehin bereits sehr lange URLs und beliebige Mengen an Header-Werten
Auch GET mit Query-Parametern ist bereits opak und macht Cache-Invalidierung einfach
Mit QUERY vor dem POST wäre das aber vermutlich besser, weil es dann nicht einfach derselbe Request mit einem Sicherheits-Flag wäre, sondern zwei unterschiedliche Request-Typen
Ich frage mich, ob HTML-Formulare QUERY-Unterstützung bekommen werden
QUERY sollte idempotent sein und könnte deshalb die lästige Warnung vor erneutem Absenden vermeiden, die beim Neuladen von Ergebnisseiten nach POST-Formularübermittlungen erscheint
Wenn
method=QUERYhinzukommt, entsteht davon nur noch eine weitere seltsame VarianteFür alle, die noch so tun wollen, als wäre noch das letzte Jahrhundert: https://www.rfc-editor.org/rfc/rfc10008.txt
„Der Ansatz, GET-Requests mit einem Body zu versehen, wurde in der IETF-Arbeitsgruppe eingehend geprüft, aber letztlich entschied man sich stattdessen für die Einführung der neuen QUERY-Methode. Die Entscheidung für eine eigene Methode beruhte auf historischen Interoperabilitätsproblemen und der strikten Einhaltung der zentralen Architekturdefinitionen von HTTP.“
Ich schicke allerdings schon seit Jahren Request-Bodys mit der GET-Methode
fetchhttps://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/U...
„GET requests cannot have a body.“
Wegen transparentem Caching kann es auch zu seltsamen Problemen kommen
Es überrascht mich, dass wir jetzt schon bei 5-stelligen RFC-Nummern angekommen sind
Jemand hatte eine absichtlich vage Wette darauf abgeschlossen, wann RFC 10000 veröffentlicht wird, aber die Nummern sprangen direkt von 9998 auf 10008. Damit hat niemand gewonnen
https://manifold.markets/CollectedOverSpread/when-will-rfc-1...
Wenn man in HTTP-Anfragen Suchergebnisse abfragen will, soll man also die QUERY-Methode verwenden und keine Query-Parameter hinzufügen
Der Name ist verwirrend. Der Begriff
querywird schließlich schon verwendet, um allgemein auf HTTP-Requests zu verweisenSchon der RFC-Titel hat mich verwirrt
querydenn verwendet, um allgemein auf HTTP-Requests zu verweisen? Umgangssprachlich bezeichnet man GET-Requests manchmal als Anfragen, aber POST, PUT oder DELETE niemals soKorrektur: Ah, für die Cache-Fähigkeit wurde QUERY wohl als nebenwirkungsfreie, „sichere“ Methode deklariert. Mein Fehler
Falls das in freier Wildbahn tatsächlich GET-Requests mit Query-String ersetzen sollte, hoffe ich sehr, dass Browser-Lesezeichen das Bewahren von Request-Parametern unterstützen werden
Ich weiß, das liegt außerhalb des Geltungsbereichs dieses RFC, aber nett daran ist, dass man das leicht erweitern könnte, sodass JS
EventSourceauch für streamende KI-Abfragen funktioniertDa der Request einen Body braucht, wird überall POST verwendet, und für Streaming-Ergebnisse kommt in der Response oft das Protokoll
text/event-streamzum Einsatz. Tatsächlich ändert sich aber kein Zustand, also passt das technisch nicht besonders gut, undEventSourcebesteht hartnäckig darauf, nur GET zu verwenden. Deshalb implementieren viele APIs dieselbe Funktionalität mit eigenen Parsern noch einmalWenn ich
GET: Content (body) "no defined semantics"sehe, denke ich zwar, dass es vielleicht okay wäre, beim GET-Method Body zu erlauben, aber laut ursprünglicher Spezifikation sollte ein GET-Body vollständig ignoriert werdenAußerdem kann Caching kaputtgehen, wenn ein wichtiger Teil der Anfrage in einem Body steckt, der entfernt wird
Wenn man GET um Body-Parameter erweitert, kann man zwei Requests mit derselben URI nicht mehr als Verweis auf dasselbe behandeln, und damit verletzt man genau diese Einschränkung der Methode