Blog

HTTP/2 vs. HTTP/1.1

Spring-Boot-Service mit HTTP/1.1 und HTTP/2 Cleartext

Die Version 2 des HTTP-Protokolls ist eigentlich dafür gedacht, nur mit SSL- bzw. TLS-Verschlüsselung verwendet zu werden. Dennoch ist es möglich, und für Testzwecke unter Umständen auch sinnvoll, die Variante h2c (HTTP/2 Cleartext) zu verwenden. Dabei findet keine Verschlüsselung statt. Kein Webbrowser und nur wenige Webserver unterstützen so etwas.

Der Java-basierte Webserver Jetty jedoch schon. Damit ist es möglich, eine kleine, auf Spring Boot basierende Beispiel-Anwendung zu bauen, um ein wenig mit h2c und HTTP-Protokoll-Upgrades herumzuspielen.

Alles, was man dazu braucht, ist eine Spring-Boot-Anwendung, bei der man den enthaltenen Spring-Boot-Webserver mit einer h2c-ConnectionFactory ausstattet:

@SpringBootApplication
public class App {

  @Bean
  public EmbeddedServletContainerCustomizer customizer() {
    return container -> {
      if (container instanceof JettyEmbeddedServletContainerFactory) {
        ((JettyEmbeddedServletContainerFactory) container)
            .addServerCustomizers(server -> {
                 ServerConnector sc = (ServerConnector) server
                   .getConnectors()[0];
                 sc.addConnectionFactory(
                   new HTTP2CServerConnectionFactory(new HttpConfiguration())
                 );
               }
            );
      }
    };
  }

  public static void main(String[] args) {
    SpringApplication.run(App.class, args);
  }
}

Wenn diese Spring-Anwendung nun einen einfachen Webservice implementiert, der über den HTTP-Port 8080 angeboten wird, spricht dieser zunächst einmal ganz einfaches HTTP/1.1.

Der HTTP-Client hat jedoch die Möglichkeit, mithilfe eines Protokoll-Upgrades einen Umstieg von HTTP/1.1 auf h2c zu fordern.

Dies kann mit einem einfachen Test-Werkzeug, wie beispielsweise nghttp ausprobiert werden:

$ nghttp -vua http://localhost:8080/hello-world

Nghttp führt einen GET-Request auf die Ressource /hello-world aus. Die Parameter -vua bewirken neben einer ausführlichen Text-Ausgabe des Befehls auch ein Protokoll-Upgrade.

[  0.002] Connected
[  0.002] HTTP Upgrade request
GET /hello-world?name=Jan HTTP/1.1
host: localhost:8080
connection: Upgrade, HTTP2-Settings
upgrade: h2c
http2-settings: AAMAAABkAAQAAP__
accept: */*
user-agent: nghttp2/1.17.0

[  0.003] HTTP Upgrade response
HTTP/1.1 101 Switching Protocols

[  0.003] HTTP Upgrade success

[  0.005] recv HEADERS frame 
              <length=67, 
              flags=0x04, 
              stream_id=1>;
          END_HEADERS
          (padlen=0);
          First response header
{"id":19,"content":"Hello, World!"}

[  0.005] recv DATA frame 
            <length=33, 
            flags=0x00, 
            stream_id=1>

Wir sehen also, dass die Spring-Anwendung sowohl HTTP/1.1/ als auch h2c über denselben Port 8080 anbieten kann.

Auf eine ähnliche Art und Weise lassen sich Spring-Boot-Services auch um HTTP/2-Konnektoren erweitern. Sie können also mit wenigen zusätzlichen Code-Zeilen dazu gebracht werden, HTTP/2 anzubieten.

Dies funktioniert dann natürlich nur mit SSL/TLS-Verschlüsselung.

Wie das funktioniert, wird auf diesem Blog in Kürze in einem weiteren Artikel erklärt.

Das komplette Code-Beispiel zu diesem Artikel ist bei Github verfügbar.

Bild: Creative Commons Attribution-Share Alike 4.0 International license. Autor: Diseño Web Valencia

Über den Autor

Antwort hinterlassen