spring-boot/spring-boot-project/spring-boot-docs/src/docs/asciidoc/web/reactive.adoc

327 lines
16 KiB
Plaintext

[[web.reactive]]
== Reactive Web Applications
Spring Boot simplifies development of reactive web applications by providing auto-configuration for Spring Webflux.
[[web.reactive.webflux]]
=== The "`Spring WebFlux Framework`"
Spring WebFlux is the new reactive web framework introduced in Spring Framework 5.0.
Unlike Spring MVC, it does not require the servlet API, is fully asynchronous and non-blocking, and implements the https://www.reactive-streams.org/[Reactive Streams] specification through https://projectreactor.io/[the Reactor project].
Spring WebFlux comes in two flavors: functional and annotation-based.
The annotation-based one is quite close to the Spring MVC model, as shown in the following example:
include::code:MyRestController[]
WebFlux is part of the Spring Framework and detailed information is available in its {spring-framework-docs}/web/webflux.html[reference documentation].
"`WebFlux.fn`", the functional variant, separates the routing configuration from the actual handling of the requests, as shown in the following example:
include::code:MyRoutingConfiguration[]
include::code:MyUserHandler[]
"`WebFlux.fn`" is part of the Spring Framework and detailed information is available in its {spring-framework-docs}/web/webflux-functional.html[reference documentation].
TIP: You can define as many `RouterFunction` beans as you like to modularize the definition of the router.
Beans can be ordered if you need to apply a precedence.
To get started, add the `spring-boot-starter-webflux` module to your application.
NOTE: Adding both `spring-boot-starter-web` and `spring-boot-starter-webflux` modules in your application results in Spring Boot auto-configuring Spring MVC, not WebFlux.
This behavior has been chosen because many Spring developers add `spring-boot-starter-webflux` to their Spring MVC application to use the reactive `WebClient`.
You can still enforce your choice by setting the chosen application type to `SpringApplication.setWebApplicationType(WebApplicationType.REACTIVE)`.
[[web.reactive.webflux.auto-configuration]]
==== Spring WebFlux Auto-configuration
Spring Boot provides auto-configuration for Spring WebFlux that works well with most applications.
The auto-configuration adds the following features on top of Spring's defaults:
* Configuring codecs for `HttpMessageReader` and `HttpMessageWriter` instances (described <<web#web.reactive.webflux.httpcodecs,later in this document>>).
* Support for serving static resources, including support for WebJars (described <<web#web.servlet.spring-mvc.static-content,later in this document>>).
If you want to keep Spring Boot WebFlux features and you want to add additional {spring-framework-docs}/web/webflux/config.html[WebFlux configuration], you can add your own `@Configuration` class of type `WebFluxConfigurer` but *without* `@EnableWebFlux`.
If you want to take complete control of Spring WebFlux, you can add your own `@Configuration` annotated with `@EnableWebFlux`.
[[web.reactive.webflux.conversion-service]]
==== Spring WebFlux Conversion Service
If you want to customize the `ConversionService` used by Spring WebFlux, you can provide a `WebFluxConfigurer` bean with an `addFormatters` method.
Conversion can also be customized using the `spring.webflux.format.*` configuration properties.
When not configured, the following defaults are used:
|===
|Property |`DateTimeFormatter`
|configprop:spring.webflux.format.date[]
|`ofLocalizedDate(FormatStyle.SHORT)`
|configprop:spring.webflux.format.time[]
|`ofLocalizedTime(FormatStyle.SHORT)`
|configprop:spring.webflux.format.date-time[]
|`ofLocalizedDateTime(FormatStyle.SHORT)`
|===
[[web.reactive.webflux.httpcodecs]]
==== HTTP Codecs with HttpMessageReaders and HttpMessageWriters
Spring WebFlux uses the `HttpMessageReader` and `HttpMessageWriter` interfaces to convert HTTP requests and responses.
They are configured with `CodecConfigurer` to have sensible defaults by looking at the libraries available in your classpath.
Spring Boot provides dedicated configuration properties for codecs, `+spring.codec.*+`.
It also applies further customization by using `CodecCustomizer` instances.
For example, `+spring.jackson.*+` configuration keys are applied to the Jackson codec.
If you need to add or customize codecs, you can create a custom `CodecCustomizer` component, as shown in the following example:
include::code:MyCodecsConfiguration[]
You can also leverage <<features#features.json.jackson.custom-serializers-and-deserializers,Boot's custom JSON serializers and deserializers>>.
[[web.reactive.webflux.static-content]]
==== Static Content
By default, Spring Boot serves static content from a directory called `/static` (or `/public` or `/resources` or `/META-INF/resources`) in the classpath.
It uses the `ResourceWebHandler` from Spring WebFlux so that you can modify that behavior by adding your own `WebFluxConfigurer` and overriding the `addResourceHandlers` method.
By default, resources are mapped on `+/**+`, but you can tune that by setting the configprop:spring.webflux.static-path-pattern[] property.
For instance, relocating all resources to `/resources/**` can be achieved as follows:
[source,yaml,indent=0,subs="verbatim",configprops,configblocks]
----
spring:
webflux:
static-path-pattern: "/resources/**"
----
You can also customize the static resource locations by using `spring.web.resources.static-locations`.
Doing so replaces the default values with a list of directory locations.
If you do so, the default welcome page detection switches to your custom locations.
So, if there is an `index.html` in any of your locations on startup, it is the home page of the application.
In addition to the "`standard`" static resource locations listed earlier, a special case is made for https://www.webjars.org/[Webjars content].
By default, any resources with a path in `+/webjars/**+` are served from jar files if they are packaged in the Webjars format.
The path can be customized with the configprop:spring.webflux.webjars-path-pattern[] property.
TIP: Spring WebFlux applications do not strictly depend on the servlet API, so they cannot be deployed as war files and do not use the `src/main/webapp` directory.
[[web.reactive.webflux.welcome-page]]
==== Welcome Page
Spring Boot supports both static and templated welcome pages.
It first looks for an `index.html` file in the configured static content locations.
If one is not found, it then looks for an `index` template.
If either is found, it is automatically used as the welcome page of the application.
This only acts as a fallback for actual index routes defined by the application.
The ordering is defined by the order of `HandlerMapping` beans which is by default the following:
[cols="1,1"]
|===
|`RouterFunctionMapping`
|Endpoints declared with `RouterFunction` beans
|`RequestMappingHandlerMapping`
|Endpoints declared in `@Controller` beans
|`RouterFunctionMapping` for the Welcome Page
|The welcome page support
|===
[[web.reactive.webflux.template-engines]]
==== Template Engines
As well as REST web services, you can also use Spring WebFlux to serve dynamic HTML content.
Spring WebFlux supports a variety of templating technologies, including Thymeleaf, FreeMarker, and Mustache.
Spring Boot includes auto-configuration support for the following templating engines:
* https://freemarker.apache.org/docs/[FreeMarker]
* https://www.thymeleaf.org[Thymeleaf]
* https://mustache.github.io/[Mustache]
When you use one of these templating engines with the default configuration, your templates are picked up automatically from `src/main/resources/templates`.
[[web.reactive.webflux.error-handling]]
==== Error Handling
Spring Boot provides a `WebExceptionHandler` that handles all errors in a sensible way.
Its position in the processing order is immediately before the handlers provided by WebFlux, which are considered last.
For machine clients, it produces a JSON response with details of the error, the HTTP status, and the exception message.
For browser clients, there is a "`whitelabel`" error handler that renders the same data in HTML format.
You can also provide your own HTML templates to display errors (see the <<web#web.reactive.webflux.error-handling.error-pages,next section>>).
Before customizing error handling in Spring Boot directly, you can leverage the {spring-framework-docs}/web/webflux/ann-rest-exceptions.html[RFC 7807 Problem Details] support in Spring WebFlux.
Spring WebFlux can produce custom error messages with the `application/problem+json` media type, like:
[source,json,indent=0,subs="verbatim"]
----
{
"type": "https://example.org/problems/unknown-project",
"title": "Unknown project",
"status": 404,
"detail": "No project found for id 'spring-unknown'",
"instance": "/projects/spring-unknown"
}
----
This support can be enabled by setting configprop:spring.webflux.problemdetails.enabled[] to `true`.
The first step to customizing this feature often involves using the existing mechanism but replacing or augmenting the error contents.
For that, you can add a bean of type `ErrorAttributes`.
To change the error handling behavior, you can implement `ErrorWebExceptionHandler` and register a bean definition of that type.
Because an `ErrorWebExceptionHandler` is quite low-level, Spring Boot also provides a convenient `AbstractErrorWebExceptionHandler` to let you handle errors in a WebFlux functional way, as shown in the following example:
include::code:MyErrorWebExceptionHandler[]
For a more complete picture, you can also subclass `DefaultErrorWebExceptionHandler` directly and override specific methods.
In some cases, errors handled at the controller or handler function level are not recorded by the <<actuator#actuator.metrics.supported.spring-webflux, metrics infrastructure>>.
Applications can ensure that such exceptions are recorded with the request metrics by setting the handled exception as a request attribute:
include::code:MyExceptionHandlingController[]
[[web.reactive.webflux.error-handling.error-pages]]
===== Custom Error Pages
If you want to display a custom HTML error page for a given status code, you can add views that resolve from `error/*`, for example by adding files to a `/error` directory.
Error pages can either be static HTML (that is, added under any of the static resource directories) or built with templates.
The name of the file should be the exact status code, a status code series mask, or `error` for a default if nothing else matches.
Note that the path to the default error view is `error/error`, whereas with Spring MVC the default error view is `error`.
For example, to map `404` to a static HTML file, your directory structure would be as follows:
[source,indent=0,subs="verbatim"]
----
src/
+- main/
+- java/
| + <source code>
+- resources/
+- public/
+- error/
| +- 404.html
+- <other public assets>
----
To map all `5xx` errors by using a Mustache template, your directory structure would be as follows:
[source,indent=0,subs="verbatim"]
----
src/
+- main/
+- java/
| + <source code>
+- resources/
+- templates/
+- error/
| +- 5xx.mustache
+- <other templates>
----
[[web.reactive.webflux.web-filters]]
==== Web Filters
Spring WebFlux provides a `WebFilter` interface that can be implemented to filter HTTP request-response exchanges.
`WebFilter` beans found in the application context will be automatically used to filter each exchange.
Where the order of the filters is important they can implement `Ordered` or be annotated with `@Order`.
Spring Boot auto-configuration may configure web filters for you.
When it does so, the orders shown in the following table will be used:
|===
| Web Filter | Order
| `WebFilterChainProxy` (Spring Security)
| `-100`
| `HttpExchangesWebFilter`
| `Ordered.LOWEST_PRECEDENCE - 10`
|===
[[web.reactive.reactive-server]]
=== Embedded Reactive Server Support
Spring Boot includes support for the following embedded reactive web servers: Reactor Netty, Tomcat, Jetty, and Undertow.
Most developers use the appropriate “Starter” to obtain a fully configured instance.
By default, the embedded server listens for HTTP requests on port 8080.
[[web.reactive.reactive-server.customizing]]
==== Customizing Reactive Servers
Common reactive web server settings can be configured by using Spring `Environment` properties.
Usually, you would define the properties in your `application.properties` or `application.yaml` file.
Common server settings include:
* Network settings: Listen port for incoming HTTP requests (`server.port`), interface address to bind to (`server.address`), and so on.
* Error management: Location of the error page (`server.error.path`) and so on.
* <<howto#howto.webserver.configure-ssl,SSL>>
* <<howto#howto.webserver.enable-response-compression,HTTP compression>>
Spring Boot tries as much as possible to expose common settings, but this is not always possible.
For those cases, dedicated namespaces such as `server.netty.*` offer server-specific customizations.
TIP: See the {spring-boot-autoconfigure-module-code}/web/ServerProperties.java[`ServerProperties`] class for a complete list.
[[web.reactive.reactive-server.customizing.programmatic]]
===== Programmatic Customization
If you need to programmatically configure your reactive web server, you can register a Spring bean that implements the `WebServerFactoryCustomizer` interface.
`WebServerFactoryCustomizer` provides access to the `ConfigurableReactiveWebServerFactory`, which includes numerous customization setter methods.
The following example shows programmatically setting the port:
include::code:MyWebServerFactoryCustomizer[]
`JettyReactiveWebServerFactory`, `NettyReactiveWebServerFactory`, `TomcatReactiveWebServerFactory`, and `UndertowReactiveWebServerFactory` are dedicated variants of `ConfigurableReactiveWebServerFactory` that have additional customization setter methods for Jetty, Reactor Netty, Tomcat, and Undertow respectively.
The following example shows how to customize `NettyReactiveWebServerFactory` that provides access to Reactor Netty-specific configuration options:
include::code:MyNettyWebServerFactoryCustomizer[]
[[web.reactive.reactive-server.customizing.direct]]
===== Customizing ConfigurableReactiveWebServerFactory Directly
For more advanced use cases that require you to extend from `ReactiveWebServerFactory`, you can expose a bean of such type yourself.
Setters are provided for many configuration options.
Several protected method "`hooks`" are also provided should you need to do something more exotic.
See the {spring-boot-module-api}/web/reactive/server/ConfigurableReactiveWebServerFactory.html[source code documentation] for details.
NOTE: Auto-configured customizers are still applied on your custom factory, so use that option carefully.
[[web.reactive.reactive-server-resources-configuration]]
=== Reactive Server Resources Configuration
When auto-configuring a Reactor Netty or Jetty server, Spring Boot will create specific beans that will provide HTTP resources to the server instance: `ReactorResourceFactory` or `JettyResourceFactory`.
By default, those resources will be also shared with the Reactor Netty and Jetty clients for optimal performances, given:
* the same technology is used for server and client
* the client instance is built using the `WebClient.Builder` bean auto-configured by Spring Boot
Developers can override the resource configuration for Jetty and Reactor Netty by providing a custom `ReactorResourceFactory` or `JettyResourceFactory` bean - this will be applied to both clients and servers.
You can learn more about the resource configuration on the client side in the <<io#io.rest-client.webclient.runtime, WebClient Runtime section>>.