HTTP/3 ist die dritte Hauptversion von HTTP, definiert in RFC 9114. Sie lässt die HTTP-Semantik unverändert und ersetzt den Transport durch QUIC.
HTTP/3 behält alles bei, was Sie bereits über HTTP wissen: dieselben Methoden, dieselben Statuscodes, dieselben Headerfelder, dieselben Caching- und Authentifizierungsregeln. Was sich ändert, ist der Träger. HTTP/1.1 und HTTP/2 laufen über TCP mit darüberliegendem TLS. HTTP/3 läuft über QUIC, einen UDP-basierten Transport mit eingebautem TLS 1.3.
Da die HTTP-Semantik unverändert bleibt, verhält sich eine von HTTP/1.1 oder HTTP/2 nach HTTP/3 portierte Anwendung genauso. Sie setzen ein GET ab, Sie erhalten einen Statuscode und einen Body zurück.
| RFC | Title | Was es definiert |
|---|---|---|
| RFC 9114 | HTTP/3 | Die Abbildung von HTTP auf QUIC: Frames, Anfrage- und Antwort-Streams, unidirektionale Stream-Typen, Einstellungen, Server-Push und die HTTP/3-Fehlercodes. |
| RFC 9204 | QPACK: Field Compression for HTTP/3 | Header-Komprimierung, die für QUIC entwickelt wurde und eine statische Tabelle sowie eine dynamische Tabelle verwendet, die auf dedizierten Encoder- und Decoder-Streams übertragen wird. |
| RFC 9000 | QUIC-Transport | Der Transport, auf dem HTTP/3 übertragen wird. Siehe QUIC. |
HTTP/2 komprimiert Header mit HPACK, das voraussetzt, dass Header in der Reihenfolge eintreffen, in der sie gesendet wurden, eine Annahme, die TCP garantiert. QUIC-Streams können in abweichender Reihenfolge zugestellt werden, daher würde HPACK Head-of-Line-Blocking auf der Komprimierungsschicht wieder einführen. QPACK löst dies, indem es Aktualisierungen der dynamischen Tabelle auf separaten unidirektionalen Streams überträgt und indem eine Anfrage nur so lange blockiert, bis die Tabelleneinträge eingetroffen sind, von denen sie tatsächlich abhängt.
| HTTP/1.1 | HTTP/2 | HTTP/3 | |
|---|---|---|---|
| Spezifikation | RFC 9112 | RFC 9113 | RFC 9114 |
| Transport | TCP | TCP | QUIC über UDP |
| Verschlüsselung | Optional, TLS darüber gelagert | In der Spezifikation optional, in der Praxis TLS | Immer aktiv, TLS 1.3 ist Teil des Transports |
| Multiplexing | Keine. Eine Anfrage gleichzeitig pro Verbindung, daher öffnen Clients mehrere Verbindungen | Viele Streams über eine TCP-Verbindung | Viele Streams, vom Transport selbst bereitgestellt |
| Head-of-Line-Blocking | Ja, auf Anfrageebene | Auf Anwendungsebene beseitigt, ein verlorenes TCP-Segment blockiert jedoch weiterhin jeden Stream | Entfällt. Ein verlorenes Paket blockiert nur die Streams, deren Daten es transportiert hat |
| Header-Komprimierung | Keine, Header sind Klartext | HPACK (RFC 7541) | QPACK (RFC 9204) |
| Nachrichtenformat | Text | Binäre Frames | Binäre Frames über QUIC-Streams |
| Handshake-Kosten | TCP-Handshake, dann ein separater TLS-Handshake | TCP-Handshake, dann ein separater TLS-Handshake | Transport und TLS in einem Flight kombiniert, mit 0-RTT bei einer wiederaufgenommenen Sitzung |
| Verbindungsmigration | Nein, die Verbindung ist an das Vier-Tupel gebunden | No | Ja, die Verbindung wird durch eine Connection-ID identifiziert |
| Server-Push | No | Ja, in der Praxis veraltet | Ja, gesteuert über Push-IDs und ein clientgesteuertes Limit |
Der Client unterstützt die zehn Methoden, die in der Aufzählung Th3Methods (sgcHTTP3_Types.pas) deklariert sind. Jede besitzt eine blockierende Methode, und die meisten haben zusätzlich eine asynchrone Variante. Diese Tabelle dient der Orientierung, siehe TsgcHTTP3Client für die vollständigen Signaturen, Überladungen und Standardwerte der Parameter.
| Methode | Aufzählungswert | Client-Methode | Async-Variante |
|---|---|---|---|
GET | h3meGet | Get | GetAsync |
HEAD | h3meHead | Head | — |
POST | h3mePost | Post | PostAsync |
PUT | h3mePut | Put | PutAsync |
DELETE | h3meDelete | Delete | DeleteAsync |
PATCH | h3mePatch | Patch | PatchAsync |
OPTIONS | h3meOptions | RequestOptions | OptionsAsync |
TRACE | h3meTrace | Trace | TraceAsync |
CONNECT | h3meConnect | Connect | ConnectAsync |
QUERY | h3meQuery | Query | QueryAsync |
Hinweise zu zweien davon:
QUERY ist die IETF-QUERY-Methode, eine Spezifikation in Arbeit. Sie ist eine sichere, idempotente Methode, die einen Anfrage-Body trägt, und deckt damit den häufigen Fall einer schreibgeschützten Abfrage ab, die zu groß oder zu strukturiert ist, um in eine URL zu passen, und die heute meist auf POST abgewälzt wird. Sie ist noch kein veröffentlichter RFC.HEAD gibt das Antwortobjekt statt einer Zeichenfolge zurück, weil eine HEAD-Antwort Header und keinen Body trägt. Es gibt keine asynchrone Variante.Ein Client kann nicht davon ausgehen, dass ein Server HTTP/3 spricht, und es gibt keinen HTTP/3-Upgrade-Handshake, der dem von HTTP/2 entspricht. Der übliche Weg zur Erkennung ist der Antwort-Header Alt-Svc (RFC 7838): ein über HTTP/1.1 oder HTTP/2 erreichter Server kündigt an, dass derselbe Origin auch über HTTP/3 unter einem bestimmten Host und Port verfügbar ist, und der Client merkt sich das für künftige Anfragen. Der Client parst diesen Header und stellt ihn über das Ereignis OnAltSvc bereit, sodass Ihre Anwendung entscheiden kann, wann umgeschaltet wird.
Ein Server kann eine Antwort pushen, die der Client nicht angefordert hat, sodass ein Client, der eine Seite abruft, keinen zweiten Roundtrip für eine Ressource benötigt, von der der Server weiß, dass sie gebraucht wird. Jeder Push trägt eine Push-ID. Der Client behält die Kontrolle: Er kündigt mit SetMaxPushId an, wie viele Pushes er akzeptiert, wird über OnPushPromise über einen eingehenden Push benachrichtigt und kann einen Push mit CancelPush ablehnen.
Extended CONNECT (RFC 9220 für HTTP/3, das den von RFC 8441 für HTTP/2 definierten Mechanismus übernimmt) verwandelt einen Anfrage-Stream in einen Tunnel für ein anderes Protokoll. Es fügt der Methode CONNECT einen :protocol-Pseudo-Header hinzu, damit der Endpunkt weiß, welches Protokoll er tunneln soll.
Es ist nur verfügbar, wenn der Server SETTINGS_ENABLE_CONNECT_PROTOCOL in seinen Einstellungen ankündigt. Der Client stellt ExtendedConnect bereit, das False zurückgibt, wenn der Server es nie angekündigt hat oder wenn der Antwortstatus kein 2xx ist. Sobald der Tunnel offen ist, schreiben Sie mit TunnelSend darauf und empfangen über OnTunnelData.
WebTransport baut auf Extended CONNECT auf. Es handelt eine Sitzung über einen Extended-CONNECT-Stream aus und gibt der Anwendung dann direkt QUIC-Streams, was für latenzarmen, bidirektionalen Verkehr außerhalb des Anfrage/Antwort-Schemas genau das Richtige ist. Die Spezifikation bietet auch Datagramme, sie können jedoch auf der QUIC-Engine, die diese Bibliothek mitliefert, nicht übertragen werden, daher ist WebTransport hier auf Streams beschränkt. Es benötigt vom Server sowohl SETTINGS_ENABLE_CONNECT_PROTOCOL als auch ein SETTINGS_WEBTRANSPORT_MAX_SESSIONS ungleich null, was der Client über ServerSupportsWebTransport prüft. Da eine Sitzung mehrere Streams auf einer QUIC-Verbindung benötigt, erfordert WebTransport die integrierte OpenSSL-QUIC-Engine, siehe QUIC. Einzelheiten finden Sie auf der Seite WebTransport.
| Komponente | Beschreibung |
|---|---|
| TsgcHTTP3Client | Sendet HTTP-Anfragen über HTTP/3, mit blockierenden und asynchronen Methoden, Alt-Svc-Erkennung, Server Push, Extended-CONNECT-Tunneln und WebTransport. |
| TsgcHTTP3Server | Nimmt HTTP/3-Verbindungen an und bedient Anfragen über QUIC. Er leitet sich von TsgcQUICServer ab und ergänzt HTTP/3-Framing, Einstellungen und Anfrageverteilung. |
| WebTransport | Sitzungen und Streams über HTTP/3, ausgehandelt mit Extended CONNECT. Datagramme werden von der ausgelieferten QUIC-Engine nicht übertragen. |
Verbinden Sie sich mit einem Host und Port und senden Sie dann Anfragen. Der Standardport ist 443.
oClient := TsgcHTTP3Client.Create(nil);
oClient.OnResponse := OnResponseHandler;
oClient.OnAltSvc := OnAltSvcHandler;
oClient.Connect('www.example.com', 443);
vBody := oClient.Get('https://www.example.com/');
oClient.Disconnect;
Der Server bindet einen UDP-Port, lädt ein Zertifikat und einen Schlüssel und löst für jede Anfrage ein Ereignis aus.
oServer := TsgcHTTP3Server.Create(nil);
oServer.Port := 443;
oServer.QUICOptions.SSLOptions.CertFile := 'cert.pem';
oServer.QUICOptions.SSLOptions.KeyFile := 'key.pem';
oServer.OnH3Request := OnH3RequestHandler;
oServer.Start;
HTTP/3 läuft über UDP, daher muss Port 443 über UDP und nicht nur über TCP erreichbar sein. Dies ist der häufigste Grund, warum eine funktionierende HTTP/2-Installation kein HTTP/3 ausliefert.
Der Server bindet die Adresse in Host. Ein Wert, der einen Doppelpunkt enthält, ist ein IPv6-Literal, und jeder andere Wert, ein IPv4-Literal oder ein Hostname, wird über beide Adressfamilien aufgelöst. Ein leeres Host bindet den Dual-Stack-Platzhalter, sodass ein einziger Listener IPv4- und IPv6-Gegenstellen auf demselben Port bedient. Der Client ist URL-gesteuert, daher gehört ein IPv6-Literal dort in eckige Klammern, zum Beispiel oClient.Get('https://[::1]:443/').
| Voraussetzung | Detail |
|---|---|
| Edition | All-Access. Das Pack SGC_PACK_HTTP3 liegt im Block SGC_EDT_ALL von sgcVer.inc. |
| Pack-Define | SGC_PACK_HTTP3. Es wird in sgcVer.inc auskommentiert ausgeliefert und muss daher ausdrücklich aktiviert werden, bevor HTTP/3 einkompiliert wird. |
| Feature-Defines | Wenn sowohl SGC_PACK_HTTP3 als auch SGC_INDY_LIB aktiviert sind, definiert sgcVer.inc die Symbole SGC_QUIC, SGC_HTTP3 und SGC_WEBTRANSPORT. Die HTTP/3-Komponenten werden unter SGC_HTTP3 kompiliert und die WebTransport-Member unter SGC_WEBTRANSPORT. |
| Indy | SGC_INDY_LIB ist erforderlich. Die HTTP/3-Defines sind in einen SGC_INDY_LIB-Guard eingebettet. |
| OpenSSL | OpenSSL 3.5 oder neuer, das standardmäßig die native QUIC-Unterstützung bereitstellt, auf der die Komponenten aufbauen. WebTransport erfordert zusätzlich die integrierte OpenSSL-QUIC-Engine. Mit dem TLS-IOHandler auf iohNativeTLS läuft HTTP/3 ohne OpenSSL auf der sgc-QUIC-Engine, siehe SSL ohne OpenSSL. |
| Units | sgcHTTP.pas deklariert die Komponenten. HTTP/3 selbst befindet sich in den sgcHTTP3_*-Units, WebTransport in sgcWebTransport.pas und der Transport in den sgcQUIC_*-Units. |
Um HTTP/3 zu aktivieren, bearbeiten Sie sgcVer.inc und heben Sie die Auskommentierung des Pack-Defines innerhalb des All-Access-Blocks auf:
{$IFDEF SGC_EDT_ALL} { ALL-ACCESS }
{$DEFINE SGC_PACK_HTML}
{$DEFINE SGC_PACK_HTTP3}
{.$DEFINE SGC_PACK_WEBRTC}
{$ENDIF}