Get ahead
VMware offers training and certification to turbo-charge your progress.
Learn moreHTTP/3, the latest major version of the Hypertext Transfer Protocol
,
had its specification finalized in June 2022. This version is designed to enhance performance, reliability, and security.
Unlike its predecessors, HTTP/3
utilizes QUIC instead of TCP
as its transport layer.
QUIC
is a UDP
-based, multiplexed, and secure transport protocol that includes built-in TLS 1.3 encryption,
making QUIC
encrypted by default.
To learn more about the performance and benefits of HTTP/3
, check out What is HTTP/3.
For information on browser adoption, take a look at Examining HTTP/3 Usage,
which also provides raw data on HTTP
versions used by different browsers.
Reactor Netty 1.2
(part of Reactor 2024.0
Release Train) adds HTTP/3
experimental support.
With this new version of Reactor Netty, your Spring Boot application and Spring Cloud Gateway can be configured to support HTTP/3
.
Let’s see how you can configure the HTTP/3
support.
Spring Boot 3.4
comes by default with Reactor 2024.0
Release Train!
If you run an older Spring Boot version, you can experiment with this new feature by bumping Reactor BOM to 2024.0
(As of this writing, 2024.0.0
is the latest version).
Maven
<properties>
<reactor-bom.version>2024.0.0</reactor-bom.version>
</properties>
Gradle
ext['reactor-bom.version'] = '2024.0.0'
You also need to add a runtime dependency on the Netty HTTP3 Codec
(As of this writing, 0.0.28.Final
is the latest version).
Maven
<dependencies>
<dependency>
<groupId>io.netty.incubator</groupId>
<artifactId>netty-incubator-codec-http3</artifactId>
<version>0.0.28.Final</version>
<scope>runtime</scope>
</dependency>
</dependencies>
Gradle
dependencies {
runtimeOnly 'io.netty.incubator:netty-incubator-codec-http3:0.0.28.Final'
}
The first thing that you need to provide is an SSL bundle with the configuration that your application requires: keystore, ciphers etc.
application.properties
spring.ssl.bundle.jks.server-http3.key.alias=http3
spring.ssl.bundle.jks.server-http3.keystore.location=...
spring.ssl.bundle.jks.server-http3.keystore.password=...
...
application.yml
spring:
ssl:
bundle:
jks:
server-http3:
key:
alias: http3
keystore:
location: ...
password: ...
...
Spring Boot gives you the ability to configure the embedded server. Spring Cloud Gateway uses the same approach to achieve this task.
You can declare a component WebServerFactoryCustomizer
and get access to the server factory.
In order to enable the HTTP/3
support you need to:
By default, Reactor Netty is configured to support HTTP/1.1
, so you need to change it.
By default, Reactor Netty does not provide any settings because those are strongly specific to the application, so you have to configure them: idle timeout, max streams, etc.
The SSL Bundle
, that was configured previously, can be obtained from the server factory via its name factory.getSslBundles().getBundle("server-http3")
and you can configure Http3SslContextSpec
.
@Component
class Http3NettyWebServerCustomizer implements WebServerFactoryCustomizer<NettyReactiveWebServerFactory> {
@Override
public void customize(NettyReactiveWebServerFactory factory) {
factory.addServerCustomizers(server -> {
SslBundle sslBundle = factory.getSslBundles().getBundle("server-http3");
Http3SslContextSpec sslContextSpec =
Http3SslContextSpec.forServer(sslBundle.getManagers().getKeyManagerFactory(), sslBundle.getKey().getPassword());
return server
// Configure HTTP/3 protocol
.protocol(HttpProtocol.HTTP3)
// Configure HTTP/3 SslContext
.secure(spec -> spec.sslContext(sslContextSpec))
// Configure HTTP/3 settings
.http3Settings(spec -> spec
.idleTimeout(Duration.ofSeconds(5))
.maxData(10_000_000)
.maxStreamDataBidirectionalRemote(1_000_000)
.maxStreamsBidirectional(100));
});
}
}
The last thing that you have to add is a simple hello
REST controller. The REST controller does not need any specific HTTP/3
configuration!
@RestController
class Http3Controller {
@GetMapping("/hello")
String hello() {
return "Hello HTTP/3!";
}
}
Now you are ready for your first HTTP/3
request:
curl --http3 https://localhost:8443/hello --verbose
* Connected to localhost (::1) port 8443
* using HTTP/3
* [HTTP/3] [0] OPENED stream for https://localhost:8443/hello
* [HTTP/3] [0] [:method: GET]
* [HTTP/3] [0] [:scheme: https]
* [HTTP/3] [0] [:authority: localhost:8443]
* [HTTP/3] [0] [:path: /hello]
* [HTTP/3] [0] [user-agent: curl]
* [HTTP/3] [0] [accept: */*]
> GET /hello HTTP/3
> Host: localhost:8443
> User-Agent: curl
> Accept: */*
>
* Request completely sent off
< HTTP/3 200
< content-type: text/plain;charset=UTF-8
< content-length: 13
<
* Connection #0 to host localhost left intact
Hello HTTP/3!
spring-webflux-http3 repository contains the complete example!
Configuring the HTTP/3
support for the client is similar to how you configure the server!
You need to:
HTTP/1.1
, so you need to change it.import reactor.netty.http.client.HttpClient;
HttpClient client = HttpClient.create()
// Configure HTTP/3 protocol
.protocol(HttpProtocol.HTTP3)
// Configure HTTP/3 settings
.http3Settings(spec -> spec
.idleTimeout(Duration.ofSeconds(5))
.maxData(10_000_000)
.maxStreamDataBidirectionalLocal(1_000_000));
By default, the client uses the standard HTTP/3
SSLContext
provided by Reactor Netty.
However, if you need more specific configuration: truststore, ciphers, etc., you can prepare SSL Bundle
similar to how you prepare it for the server
and you can configure Http3SslContextSpec
.
SslBundle sslBundle = factory.getSslBundles().getBundle("client-http3");
Http3SslContextSpec sslContextSpec = Http3SslContextSpec.forClient()
// Configure TrustStore etc.
.configure(...);
HttpClient client = HttpClient.create()
...
// Configure HTTP/3 SslContext
.secure(spec -> spec.sslContext(sslContextSpec));
You can configure the underlying Reactor Netty HttpClient
, using ReactorClientHttpConnector
.
@Bean
WebClient http3WebClient(WebClient.Builder builder) {
HttpClient client = ...;
return builder.clientConnector(new ReactorClientHttpConnector(client)).build();
}
You can create a simple REST controller that makes a remote call utilizing the new HTTP/3
configuration.
The REST controller does not need any specific HTTP/3
configuration!
@RestController
class Http3Controller {
private final WebClient http3WebClient;
Http3Controller(WebClient http3WebClient) {
this.http3WebClient = http3WebClient;
}
@GetMapping("/remote")
Mono<String> remote() {
return http3WebClient
.get()
.uri("https://projectreactor.io/")
.retrieve()
.bodyToMono(String.class);
}
}
spring-webflux-http3 repository contains the complete example.
You can configure the underlying Reactor Netty HttpClient
, using ReactorNettyClientRequestFactory
.
@Bean
RestClient http3RestClient(RestClient.Builder builder) {
HttpClient client = ...;
return builder.requestFactory(new ReactorNettyClientRequestFactory(client)).build();
}
You can create a simple REST controller that makes a remote call utilizing the new HTTP/3
configuration.
The REST controller does not need any specific HTTP/3
configuration!
@RestController
class Http3Controller {
private final RestClient http3RestClient;
Http3Controller(RestClient http3RestClient) {
this.http3RestClient = http3RestClient;
}
@GetMapping("/remote")
String remote() {
return http3RestClient
.get()
.uri("https://projectreactor.io/")
.retrieve()
.body(String.class);
}
}
spring-webmvc-http3 repository contains the complete example.
Now you are ready for your first HTTP/3
remote call:
curl --http3 https://localhost:8443/remote --verbose
* Connected to localhost (::1) port 8443
* using HTTP/3
* [HTTP/3] [0] OPENED stream for https://localhost:8443/remote
* [HTTP/3] [0] [:method: GET]
* [HTTP/3] [0] [:scheme: https]
* [HTTP/3] [0] [:authority: localhost:8443]
* [HTTP/3] [0] [:path: /remote]
* [HTTP/3] [0] [user-agent: curl/8]
* [HTTP/3] [0] [accept: */*]
> GET /remote HTTP/3
> Host: localhost:8443
> User-Agent: curl/8
> Accept: */*
>
* Request completely sent off
< HTTP/3 200
< content-type: text/plain;charset=UTF-8
< content-length: 17138
...
You can configure the underlying Reactor Netty HttpClient
, using HttpClientCustomizer
in Spring Cloud Gateway.
To use this customizer, you need to register it with the Spring Cloud Gateway configuration.
@Configuration
class GatewayConfiguration {
@Bean
HttpClientCustomizer http3HttpClientCustomizer() {
return httpClient ->
httpClient
// Configure HTTP/3 protocol
.protocol(HttpProtocol.HTTP3)
// Configure HTTP/3 settings
.http3Settings(spec -> spec.idleTimeout(Duration.ofSeconds(5))
.maxData(10_000_000)
.maxStreamDataBidirectionalLocal(1_000_000));
}
}
spring-cloud-gateway-http3 repository contains the complete example.
We hope you will enjoy the simplicity of our integration with HTTP/3
. Do reach out in our GitHub/Twitter with feedback!