Reactor Netty
provides the easy-to-use and easy-to-configure
HttpServer
class.
It hides most of the Netty
functionality that is needed in order to create a HTTP
server
and adds Reactive Streams
backpressure.
To start an HTTP server, you must create and configure a
HttpServer instance.
By default, the host
is configured for any local address, and the system picks up an ephemeral port
when the bind
operation is invoked.
The following example shows how to create an HttpServer
instance:
link:./../../reactor-netty-examples/src/main/java/reactor/netty/examples/documentation/http/server/create/Application.java[role=include]
-
Creates an HttpServer instance ready for configuring.
-
Starts the server in a blocking fashion and waits for it to finish initializing.
The returned DisposableServer
offers a simple server API, including disposeNow()
,
which shuts the server down in a blocking fashion.
To serve on a specific host
and port
, you can apply the following configuration to the HTTP
server:
link:./../../reactor-netty-examples/src/main/java/reactor/netty/examples/documentation/http/server/address/Application.java[role=include]
-
Configures the
HTTP
server host -
Configures the
HTTP
server port
To serve on multiple addresses, after having configured the HttpServer
you can bind it multiple times to obtain separate DisposableServer`s.
All created servers will share resources such as `LoopResources
because they use the same configuration instance under the hood.
link:./../../reactor-netty-examples/src/main/java/reactor/netty/examples/documentation/http/server/address/MultiAddressApplication.java[role=include]
-
Configures the first
HTTP
server host -
Configures the first
HTTP
server port -
Configures the second
HTTP
server host -
Configures the second
HTTP
server port
By default, the initialization of the HttpServer
resources happens on demand. This means that the bind
operation
absorbs the extra time needed to initialize and load:
-
the event loop groups
-
the native transport libraries (when native transport is used)
-
the native libraries for the security (in case of
OpenSsl
)
When you need to preload these resources, you can configure the HttpServer
as follows:
link:./../../reactor-netty-examples/src/main/java/reactor/netty/examples/documentation/http/server/warmup/Application.java[role=include]
-
Initialize and load the event loop groups, the native transport libraries and the native libraries for the security
Defining routes for the HTTP
server requires configuring the provided
HttpServerRoutes
builder.
The following example shows how to do so:
link:./../../reactor-netty-examples/src/main/java/reactor/netty/examples/documentation/http/server/routing/Application.java[role=include]
-
Serves a
GET
request to/hello
and returnsHello World!
-
Serves a
POST
request to/echo
and returns the received request body as a response. -
Serves a
GET
request to/path/{param}
and returns the value of the path parameter. -
Serves websocket to
/ws
and returns the received incoming data as outgoing data.
Note
|
The server routes are unique and only the first matching in order of declaration is invoked. |
The following code shows how you can configure the HTTP
server to serve Server-Sent Events
:
link:./../../reactor-netty-examples/src/main/java/reactor/netty/examples/documentation/http/server/sse/Application.java[role=include]
The following code shows how you can configure the HTTP
server to serve static resources:
link:./../../reactor-netty-examples/src/main/java/reactor/netty/examples/documentation/http/server/staticresources/Application.java[role=include]
To send data to a connected client, you must attach an I/O handler by using either
handle(…)
or
route(…)
.
The I/O handler has access to HttpServerResponse
,
to be able to write data. The following example uses the handle(…)
method:
link:./../../reactor-netty-examples/src/main/java/reactor/netty/examples/documentation/http/server/send/Application.java[role=include]
-
Sends
hello
string to the connected clients
When you send data to the connected clients, you may need to send additional headers,
cookies, status code, and other metadata.
You can provide this additional metadata by using
HttpServerResponse
.
The following example shows how to do so:
link:./../../reactor-netty-examples/src/main/java/reactor/netty/examples/documentation/http/server/send/headers/Application.java[role=include]
You can configure the HTTP
server to send a compressed response, depending on the request header
Accept-Encoding
.
Reactor Netty
provides three different strategies for compressing the outgoing data:
-
compress(boolean)
: Depending on the boolean that is provided, the compression is enabled (true
) or disabled (false
). -
compress(int)
: The compression is performed once the response size exceeds the given value (in bytes). -
compress(BiPredicate<HttpServerRequest, HttpServerResponse>)
: The compression is performed if the predicate returnstrue
.
The following example uses the compress
method (set to true
) to enable compression:
link:./../../reactor-netty-examples/src/main/java/reactor/netty/examples/documentation/http/server/compression/Application.java[role=include]
To receive data from a connected client, you must attach an I/O handler by using either
handle(…)
or
route(…)
.
The I/O handler has access to HttpServerRequest
,
to be able to read data.
The following example uses the handle(…)
method:
link:./../../reactor-netty-examples/src/main/java/reactor/netty/examples/documentation/http/server/read/Application.java[role=include]
-
Receives data from the connected clients
When you receive data from the connected clients, you might need to check request headers,
parameters, and other metadata. You can obtain this additional metadata by using
HttpServerRequest
.
The following example shows how to do so:
link:./../../reactor-netty-examples/src/main/java/reactor/netty/examples/documentation/http/server/read/headers/Application.java[role=include]
When you receive data from the connected clients, you might want to access POST
form
(application/x-www-form-urlencoded
) or
multipart
(multipart/form-data
) data. You can obtain this data by using
HttpServerRequest
.
link:./../../reactor-netty-examples/src/main/java/reactor/netty/examples/documentation/http/server/multipart/Application.java[role=include]
-
Receives
POST
form/multipart data.
When you need to change the default settings, you can configure the HttpServer
or you can provide a configuration per request:
link:./../../reactor-netty-examples/src/main/java/reactor/netty/examples/documentation/http/server/multipart/custom/Application.java[role=include]
-
Configuration on the
HttpServer
that specifies that the data is stored on disk only. -
Configuration per request that specifies that if the data size exceed the specified size, the data is stored on the disk.
The following listing shows the available configurations:
Configuration name | Description |
---|---|
|
Configures the directory where to store the data on the disk. Default to generated temp directory. |
|
Configures the |
|
Configures the maximum in-memory size per data i.e. the data is written
on disk if the size is greater than |
|
Configures the maximum size per data. When the limit is reached, an exception is raised.
If set to |
|
Configures the scheduler to be used for offloading disk operations in the decoding phase.
Default to |
|
When set to |
In addition to the metadata that you can obtain from the request, you can also receive the
host (server)
address, the remote (client)
address and the scheme
. Depending on the
chosen factory method, you can retrieve the information directly from the channel or by
using the Forwarded
or X-Forwarded-*
HTTP
request headers.
The following example shows how to do so:
link:./../../reactor-netty-examples/src/main/java/reactor/netty/examples/documentation/http/server/clientaddress/Application.java[role=include]
-
Specifies that the information about the connection is to be obtained from the
Forwarded
andX-Forwarded-*
HTTP
request headers, if possible. -
Returns the address of the remote (client) peer.
It is also possible to customize the behavior of the Forwarded
or X-Forwarded-*
header handler.
The following example shows how to do so:
link:./../../reactor-netty-examples/src/main/java/reactor/netty/examples/documentation/http/server/clientaddress/CustomForwardedHeaderHandlerApplication.java[role=include]
-
Add a custom header handler.
-
Returns the address of the remote (client) peer.
By default, Netty
configures some restrictions for the incoming requests, such as:
-
The maximum length of the initial line.
-
The maximum length of all headers.
-
The maximum length of the content or each chunk.
For more information, see HttpRequestDecoder
and HttpServerUpgradeHandler
By default, the HTTP
server is configured with the following settings:
link:./../../reactor-netty-http/src/main/java/reactor/netty/http/HttpDecoderSpec.java[role=include]
link:./../../reactor-netty-http/src/main/java/reactor/netty/http/server/HttpRequestDecoderSpec.java[role=include]
When you need to change these default settings, you can configure the HTTP
server as follows:
link:./../../reactor-netty-examples/src/main/java/reactor/netty/examples/documentation/http/server/requestdecoder/Application.java[role=include]
-
The maximum length of all headers will be
16384
. When this value is exceeded, a TooLongFrameException is raised.
The following lifecycle callbacks are provided to let you extend the HttpServer
:
Callback | Description |
---|---|
|
Invoked when the server channel is about to bind. |
|
Invoked when the server channel is bound. |
|
Invoked when initializing the channel. |
|
Invoked when a remote client is connected |
|
Invoked when the server channel is unbound. |
The following example uses the doOnConnection
and doOnChannelInit
callbacks:
link:./../../reactor-netty-examples/src/main/java/reactor/netty/examples/documentation/http/server/lifecycle/Application.java[role=include]
-
Netty
pipeline is extended withReadTimeoutHandler
when a remote client is connected. -
Netty
pipeline is extended withLoggingHandler
when initializing the channel.
When you need to change configuration on the TCP level, you can use the following snippet
to extend the default TCP
server configuration:
link:./../../reactor-netty-examples/src/main/java/reactor/netty/examples/documentation/http/server/channeloptions/Application.java[role=include]
See [tcp-server] for more detail about TCP-level configuration.
When you need SSL or TLS, you can apply the configuration shown in the next example.
By default, if OpenSSL
is available,
SslProvider.OPENSSL
provider is used as a provider. Otherwise
SslProvider.JDK
is used.
You can switch the provider by using
SslContextBuilder
or by setting -Dio.netty.handler.ssl.noOpenSsl=true
.
The following example uses SslContextBuilder
:
link:./../../reactor-netty-examples/src/main/java/reactor/netty/examples/documentation/http/server/security/Application.java[role=include]
You can configure the HTTP
server with multiple SslContext
mapped to a specific domain.
An exact domain name or a domain name containing a wildcard can be used when configuring the SNI
mapping.
The following example uses a domain name containing a wildcard:
link:./../../reactor-netty-examples/src/main/java/reactor/netty/examples/documentation/http/server/sni/Application.java[role=include]
You can enable the HTTP
access log either programmatically or by configuration. By default, it is disabled.
You can use -Dreactor.netty.http.server.accessLogEnabled=true
to enable the HTTP
access log by configuration.
You can use the following configuration (for Logback or similar logging frameworks) to have a separate
HTTP
access log file:
<appender name="accessLog" class="ch.qos.logback.core.FileAppender">
<file>access_log.log</file>
<encoder>
<pattern>%msg%n</pattern>
</encoder>
</appender>
<appender name="async" class="ch.qos.logback.classic.AsyncAppender">
<appender-ref ref="accessLog" />
</appender>
<logger name="reactor.netty.http.server.AccessLog" level="INFO" additivity="false">
<appender-ref ref="async"/>
</logger>
The following example enables it programmatically:
link:./../../reactor-netty-examples/src/main/java/reactor/netty/examples/documentation/http/server/accessLog/Application.java[role=include]
Calling this method takes precedence over the system property configuration.
By default, the logging format is Common Log Format, but you can specify a custom one as a parameter, as in the following example:
link:./../../reactor-netty-examples/src/main/java/reactor/netty/examples/documentation/http/server/accessLog/CustomLogAccessFormatApplication.java[role=include]
You can also filter HTTP
access logs by using the AccessLogFactory#createFilter
method, as in the following example:
link:./../../reactor-netty-examples/src/main/java/reactor/netty/examples/documentation/http/server/accessLog/FilterLogAccessApplication.java[role=include]
Note that this method can take a custom format parameter too, as in this example:
link:./../../reactor-netty-examples/src/main/java/reactor/netty/examples/documentation/http/server/accessLog/CustomFormatAndFilterAccessLogApplication.java[role=include]
-
Specifies the filter predicate to use
-
Specifies the custom format to apply
By default, the HTTP
server supports HTTP/1.1
. If you need HTTP/2
, you can get it through configuration.
In addition to the protocol configuration, if you need H2
but not H2C (cleartext)
, you must also configure SSL.
Note
|
As Application-Layer Protocol Negotiation (ALPN) is not supported “out-of-the-box” by JDK8 (although some vendors backported ALPN to JDK8), you need an additional dependency to a native library that
supports it — for example, netty-tcnative-boringssl-static .
|
The following listing presents a simple H2
example:
link:./../../reactor-netty-examples/src/main/java/reactor/netty/examples/documentation/http/server/http2/H2Application.java[role=include]
-
Configures the server to support only
HTTP/2
-
Configures
SSL
The application should now behave as follows:
$ curl --http2 https://localhost:8080 -i
HTTP/2 200
hello
The following listing presents a simple H2C
example:
link:./../../reactor-netty-examples/src/main/java/reactor/netty/examples/documentation/http/server/http2/H2CApplication.java[role=include]
The application should now behave as follows:
$ curl --http2-prior-knowledge http://localhost:8080 -i
HTTP/2 200
hello
The HTTP server supports built-in integration with Micrometer
.
It exposes all metrics with a prefix of reactor.netty.http.server
.
The following table provides information for the HTTP server metrics:
metric name | type | description |
---|---|---|
reactor.netty.http.server.streams.active |
Gauge |
The number of active HTTP/2 streams. |
reactor.netty.http.server.connections.active |
Gauge |
The number of http connections currently processing requests |
reactor.netty.http.server.connections.total |
Gauge |
The number of all opened connections |
reactor.netty.http.server.data.received |
DistributionSummary |
Amount of the data received, in bytes |
reactor.netty.http.server.data.sent |
DistributionSummary |
Amount of the data sent, in bytes |
reactor.netty.http.server.errors |
Counter |
Number of errors that occurred |
reactor.netty.http.server.data.received.time |
Timer |
Time spent in consuming incoming data |
reactor.netty.http.server.data.sent.time |
Timer |
Time spent in sending outgoing data |
reactor.netty.http.server.response.time |
Timer |
Total time for the request/response |
These additional metrics are also available:
The following example enables that integration:
link:./../../reactor-netty-examples/src/main/java/reactor/netty/examples/documentation/http/server/metrics/Application.java[role=include]
-
Applies upper limit for the meters with
URI
tag -
Templated URIs will be used as an URI tag value when possible
-
Enables the built-in integration with Micrometer
Note
|
In order to avoid a memory and CPU overhead of the enabled metrics, it is important to convert the real URIs to templated URIs when possible. Without a conversion to a template-like form, each distinct URI leads to the creation of a distinct tag, which takes a lot of memory for the metrics. |
Note
|
Always apply an upper limit for the meters with URI tags. Configuring an upper limit on the number of meters can help in cases when the real URIs cannot be templated.
You can find more information at maximumAllowableTags .
|
When HTTP server metrics are needed for an integration with a system other than Micrometer
or you want
to provide your own integration with Micrometer
, you can provide your own metrics recorder, as follows:
link:./../../reactor-netty-examples/src/main/java/reactor/netty/examples/documentation/http/server/metrics/custom/Application.java[role=include]
-
Enables HTTP server metrics and provides
HttpServerMetricsRecorder
implementation.
The HTTP
server supports Unix Domain Sockets (UDS) when native transport is in use.
The following example shows how to use UDS support:
link:./../../reactor-netty-examples/src/main/java/reactor/netty/examples/documentation/http/server/uds/Application.java[role=include]
-
Specifies
DomainSocketAddress
that will be used