Server-Side HTTP/2 (Preview)

Warning

Server-Side HTTP/2 support in akka-http is currently available as a preview. This means it is ready to be evaluated, but the APIs and behavior are likely to change.

Dependency

To use Akka HTTP2 Support, add the module to your project:

sbt
libraryDependencies += "com.typesafe.akka" %% "akka-http2-support" % "10.1.3"
Gradle
dependencies {
  compile group: 'com.typesafe.akka', name: 'akka-http2-support_2.12', version: '10.1.3'
}
Maven
<dependency>
  <groupId>com.typesafe.akka</groupId>
  <artifactId>akka-http2-support_2.12</artifactId>
  <version>10.1.3</version>
</dependency>

Enable HTTP/2 support

HTTP/2 can then be enabled through configuration:

akka.http.server.preview.enable-http2 = on

Use bindAndHandleAsync and HTTPS

HTTP/2 is primarily used over a secure connection (known as “over HTTPS” or “with TLS”), which also takes care of protocol negotiation and falling back to plain HTTPS when the client does not support HTTP/2. See the HTTPS section for how to set up HTTPS.

You can use Http().bindAndHandleAsyncHttp().get(system).bindAndHandleAsync() as long as you followed the above steps:

Scala
import scala.concurrent.Future

import akka.http.scaladsl.{ Http, HttpsConnectionContext }
import akka.http.scaladsl.Http2

  Http().bindAndHandleAsync(
    asyncHandler,
    interface = "localhost",
    port = 8443,
    httpsServerContext)
Java
import akka.http.javadsl.Http;
import static akka.http.javadsl.ConnectHttp.toHostHttps;

    Http.get(system)
      .bindAndHandleAsync(
        asyncHandler,
        toHostHttps("127.0.0.1", 8443).withCustomHttpsContext(httpsConnectionContext),
        materializer);

Note that bindAndHandle currently does not support HTTP/2, you must use bindAndHandleAsync.

HTTP/2 without HTTPS

While un-encrypted connections are allowed by HTTP/2, this is generally discouraged.

There are 2 ways to implement un-encrypted HTTP/2 connections: by using the HTTP Upgrade mechanism or by starting communication in HTTP/2 directly. The latter only makes sense when you can assume the client has Prior Knowledge of HTTP/2 support.

We currently only support the approach requiring Prior Knowledge:

Scala
import akka.http.scaladsl.Http2
import akka.http.scaladsl.HttpConnectionContext
import akka.http.scaladsl.UseHttp2.Always

  Http2().bindAndHandleAsync(
    asyncHandler,
    interface = "localhost",
    port = 8080,
    connectionContext = HttpConnectionContext(http2 = Always))
Java
import akka.http.javadsl.UseHttp2;
import static akka.http.javadsl.ConnectHttp.toHost;

    Http.get(system)
      .bindAndHandleAsync(
        asyncHandler,
        toHost("127.0.0.1", 8080, UseHttp2.always()),
        materializer);

Testing with cURL

At this point you should be able to connect, but HTTP/2 may still not be available.

You’ll need a recent version of cURL compiled with HTTP/2 support (for OSX see this article). You can check whether your version supports HTTP2 with curl --version, look for the nghttp2 extension and the HTTP2 feature:

curl 7.52.1 (x86_64-pc-linux-gnu) libcurl/7.52.1 OpenSSL/1.0.2l zlib/1.2.8 libidn2/0.16 libpsl/0.17.0 (+libidn2/0.16) libssh2/1.8.0 nghttp2/1.23.1 librtmp/2.3
Protocols: dict file ftp ftps gopher http https imap imaps ldap ldaps pop3 pop3s rtmp rtsp scp sftp smb smbs smtp smtps telnet tftp
Features: AsynchDNS IDN IPv6 Largefile GSS-API Kerberos SPNEGO NTLM NTLM_WB SSL libz TLS-SRP HTTP2 UnixSockets HTTPS-proxy PSL

When you connect to your service you may now see something like:

$ curl -k -v https://localhost:8443
(...)
* ALPN, offering h2
* ALPN, offering http/1.1
(...)
* ALPN, server accepted to use h2
(...)
> GET / HTTP/1.1
(...)
< HTTP/2 200
(...)

If your curl output looks like above, you have successfully configured HTTP/2. However, on JDKs up to version 9, it is likely to look like this instead:

$ curl -k -v https://localhost:8443
(...)
* ALPN, offering h2
* ALPN, offering http/1.1
(...)
* ALPN, server did not agree to a protocol
(...)
> GET / HTTP/1.1
(...)
< HTTP/1.1 200 OK
(...)

This shows curl declaring it is ready to speak h2 (the shorthand name of HTTP/2), but could not determine whether the server is ready to, so it fell back to HTTP/1.1. To make this negotiation work you’ll have to configure ALPN as described below.

Application-Layer Protocol Negotiation (ALPN)

Application-Layer Protocol Negotiation (ALPN) is used to negotiate whether both client and server support HTTP/2.

ALPN support comes with the JVM starting from version 9. If you’re on a previous version of the JVM, you’ll have to load a Java Agent to provide this functionality. We recommend the agent from the Jetty project, jetty-alpn-agent.

manually

This agent can be loaded with the -javaagent JVM option:

  java -javaagent:/path/to/jetty-alpn-agent-2.0.7.jar -jar app.jar

sbt

sbt can be configured to load the agent with the sbt-javaagent plugin:

  .enablePlugins(JavaAgent)
  .settings(
    javaAgents += "org.mortbay.jetty.alpn" % "jetty-alpn-agent" % "2.0.7" % "runtime"
  )

This should automatically load the agent when running, testing, or even in distributions made with sbt-native-package.

maven

To configure maven to load the agent when running mvn exec:exec, add it as a ‘runtime’ dependency:

<dependency>
    <groupId>org.mortbay.jetty.alpn</groupId>
    <artifactId>jetty-alpn-agent</artifactId>
    <version>2.0.7</version>
    <scope>runtime</scope>
</dependency>

and use the maven-dependency-plugin:

<plugin>
    <artifactId>maven-dependency-plugin</artifactId>
    <version>2.5.1</version>
    <executions>
        <execution>
            <id>getClasspathFilenames</id>
            <goals>
                <goal>properties</goal>
            </goals>
        </execution>
     </executions>
</plugin>

to add it to the exec-maven-plugin arguments:

<plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>exec-maven-plugin</artifactId>
    <version>1.6.0</version>
    <configuration>
        <executable>java</executable>
        <arguments>
            <argument>-javaagent:${org.mortbay.jetty.alpn:jetty-alpn-agent:jar}</argument>
            <argument>-classpath</argument>
            <classpath />
            <argument>com.example.HttpServer</argument>
        </arguments>
    </configuration>
</plugin>
Found an error in this documentation? The source code for this page can be found here. Please feel free to edit and contribute a pull request.