The `spring-test` module provides mock implementations of `ServerHttpRequest`,
`ServerHttpResponse`, and `ServerWebExchange`.
See <<testing.adoc#mock-objects-web-reactive,Spring Web Reactive>> mock objects.
See <<testing.adoc#mock-objects-web-reactive,Spring Web Reactive>> for a discussion of mock objects.
The <<testing.adoc#webtestclient,WebTestClient>> builds on these mock request and
response objects to provide support for testing WebFlux applications without and HTTP
server. The `WebTestClient` can be used for end-to-end integration tests too.
<<testing.adoc#webtestclient,`WebTestClient`>> builds on these mock request and
response objects to provide support for testing WebFlux applications without an HTTP
server. You can use the `WebTestClient` for end-to-end integration tests, too.
[[webflux-threading-model]]
=== Threading model
//[[webflux-threading-model]]
//=== Threading model
// TODO Once we have content for this heading, we should un-comment the heading and
// anchor. Until then, we should leave it commented.
@ -49,30 +48,27 @@ server. The `WebTestClient` can be used for end-to-end integration tests too.
@@ -49,30 +48,27 @@ server. The `WebTestClient` can be used for end-to-end integration tests too.
== Reactive Libraries
`spring-webflux` depends on `reactor-core` and uses it internally to compose asynchronous
logic and to provide Reactive Streams support. Generally WebFlux APIs return `Flux` or
`Mono` -- since that's what's used internally, and leniently accept any Reactive Streams
`Publisher` implementation as input. The use of `Flux` vs `Mono` is important because it
helps to express cardinality -- e.g. whether a single or multiple async values are
expected, and that can be essential for making decisions, for example when encoding or
decoding HTTP messages.
logic and to provide Reactive Streams support. Generally, WebFlux APIs return `Flux` or
`Mono` (since those are used internally) and leniently accept any Reactive Streams
`Publisher` implementation as input. The use of `Flux` versus `Mono` is important, because it
helps to express cardinality -- for example, whether a single or multiple asynchronous values are
expected, and that can be essential for making decisions (for example, when encoding or
decoding HTTP messages).
For annotated controllers, WebFlux transparently adapts to the reactive library chosen by
the application. This is done with the help of the
{api-spring-framework}/core/ReactiveAdapterRegistry.html[ReactiveAdapterRegistry] which
{api-spring-framework}/core/ReactiveAdapterRegistry.html[`ReactiveAdapterRegistry`], which
provides pluggable support for reactive library and other asynchronous types. The registry
has built-in support for RxJava and `CompletableFuture`, but others can be registered too.
has built-in support for RxJava and `CompletableFuture`, but you can register others, too.
For functional APIs such as <<webflux-fn>>, the `WebClient`, and others, the general rules
for WebFlux APIs apply -- `Flux` and `Mono` as return values, and Reactive Streams
For functional APIs (such as <<webflux-fn>>, the `WebClient`, and others), the general rules
for WebFlux APIs apply -- `Flux` and `Mono` as return values and a Reactive Streams
`Publisher` as input. When a `Publisher`, whether custom or from another reactive library,
is provided, it can only be treated as a stream with unknown semantics (0..N). If however
is provided, it can be treated only as a stream with unknown semantics (0..N). If, however,
the semantics are known, you can wrap it with `Flux` or `Mono.from(Publisher)` instead
of passing the raw `Publisher`.
[NOTE]
====
For example, given a `Publisher` that is not a `Mono`, the Jackson JSON message writer
expects multiple values. If the media type implies an infinite stream -- e.g.
`"application/json+stream"`, values are written and flushed individually; otherwise
expects multiple values. If the media type implies an infinite stream (for example,
`application/json+stream`), values are written and flushed individually. Otherwise,
values are buffered into a list and rendered as a JSON array.
class is for convenience, so you don't have to remember the name of the `ServletContext`
attribute. Its __getWebApplicationContext()__ method will return `null` if an object
doesn't exist under the `WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE`
key. Rather than risk getting `NullPointerExceptions` in your application, it's better
class is for convenience, so you need not remember the name of the `ServletContext`
attribute. Its `getWebApplicationContext()` method returns `null` if an object
does not exist under the `WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE`
key. Rather than risk getting `NullPointerExceptions` in your application, it is better
to use the `getRequiredWebApplicationContext()` method. This method throws an exception
when the `ApplicationContext` is missing.
@ -99,29 +100,26 @@ their implemented interfaces.
@@ -99,29 +100,26 @@ their implemented interfaces.
Fortunately, most of the frameworks in this section have simpler ways of looking up
beans. Not only do they make it easy to get beans from a Spring container, but they also
allow you to use dependency injection on their controllers. Each web framework section
let you use dependency injection on their controllers. Each web framework section
has more detail on its specific integration strategies.
[[jsf]]
== JSF
JavaServer Faces (JSF) is the JCP's standard component-based, event-driven web user
interface framework. As of Java EE 5, it is an official part of the Java EE umbrella.
For a popular JSF runtime as well as for popular JSF component libraries, check out the
http://myfaces.apache.org/[Apache MyFaces project]. The MyFaces project also provides
common JSF extensions such as http://myfaces.apache.org/orchestra/[MyFaces Orchestra]:
a Spring-based JSF extension that provides rich conversation scope support.
common JSF extensions, such as http://myfaces.apache.org/orchestra/[MyFaces Orchestra]
(a Spring-based JSF extension that provides rich conversation scope support).
[NOTE]
====
Spring Web Flow 2.0 provides rich JSF support through its newly established Spring Faces
NOTE: Spring Web Flow 2.0 provides rich JSF support through its newly established Spring Faces
module, both for JSF-centric usage (as described in this section) and for Spring-centric
usage (using JSF views within a Spring MVC dispatcher). Check out the
http://projects.spring.io/spring-webflow[Spring Web Flow website] for details!
====
usage (using JSF views within a Spring MVC dispatcher). See the
http://projects.spring.io/spring-webflow[Spring Web Flow website] for details.
The key element in Spring's JSF integration is the JSF `ELResolver` mechanism.
@ -129,15 +127,17 @@ The key element in Spring's JSF integration is the JSF `ELResolver` mechanism.
@@ -129,15 +127,17 @@ The key element in Spring's JSF integration is the JSF `ELResolver` mechanism.
[[jsf-springbeanfaceselresolver]]
=== Spring Bean Resolver
`SpringBeanFacesELResolver` is a JSF 1.2+ compliant `ELResolver` implementation,
integrating with the standard Unified EL as used by JSF 1.2 and JSP 2.1. Like
`SpringBeanVariableResolver`, it delegates to the Spring's 'business context'
`WebApplicationContext` __first__, then to the default resolver of the underlying JSF
integrating with the standard Unified EL as used by JSF 1.2 and JSP 2.1. As
`SpringBeanVariableResolver`, it delegates to Spring's "`business context`"
`WebApplicationContext` first and then to the default resolver of the underlying JSF
implementation.
Configuration-wise, simply define `SpringBeanFacesELResolver` in your JSF
__faces-context.xml__ file:
Configuration-wise, you can define `SpringBeanFacesELResolver` in your JSF
`faces-context.xml` file, as the following example shows:
`UriComponentsBuilder` helps to build URI's from URI templates with variables:
`UriComponentsBuilder` helps to build URI's from URI templates with variables, as the following example shows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -17,13 +18,16 @@
@@ -17,13 +18,16 @@
URI uri = uriComponents.expand("Westin", "123").toUri(); // <5>
----
<1> Static factory method with a URI template.
<2> Add and/or replace URI components.
<2> Add or replace URI components.
<3> Request to have the URI template and URI variables encoded.
<4> Build a `UriComponents`.
<5> Expand variables, and obtain the `URI`.
<5> Expand variables and obtain the `URI`.
====
The above can be consolidated into one chain and shortened with `buildAndExpand`:
The preceding example can be consolidated into one chain and shortened with `buildAndExpand`,
as the following example shows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -34,9 +38,12 @@ The above can be consolidated into one chain and shortened with `buildAndExpand`
@@ -34,9 +38,12 @@ The above can be consolidated into one chain and shortened with `buildAndExpand`
.buildAndExpand("Westin", "123")
.toUri();
----
====
It can be shortened further by going directly to URI (which implies encoding):
You can shorten it further by going directly to a URI (which implies encoding),
as the following example shows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -45,9 +52,11 @@ It can be shortened further by going directly to URI (which implies encoding):
@@ -45,9 +52,11 @@ It can be shortened further by going directly to URI (which implies encoding):
.queryParam("q", "{q}")
.build("Westin", "123");
----
====
Or shorter further yet, with a full URI template:
You shorter it further still with a full URI template, as the following example shows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -55,24 +64,27 @@ Or shorter further yet, with a full URI template:
@@ -55,24 +64,27 @@ Or shorter further yet, with a full URI template:
Encodes URI components _after_ URI variables are expanded.
Both options replace non-ASCII and illegal characters with escaped octets, however option
1 also replaces characters with reserved meaning that appear in URI variables.
Both options replace non-ASCII and illegal characters with escaped octets. However, the first option
also replaces characters with reserved meaning that appear in URI variables.
[TIP]
====
Consider ";" which is legal in a path but has reserved meaning. Option 1 replaces
";" with "%3B" in URI variables but not in the URI template. By contrast, option 2 never
replaces ";" since it is a legal character in a path.
====
TIP: Consider ";", which is legal in a path but has reserved meaning. The first option replaces
";" with "%3B" in URI variables but not in the URI template. By contrast, the second option never
replaces ";", since it is a legal character in a path.
For most cases option 1 is likely to give the expected result because it treats URI
For most cases, the first option is likely to give the expected result, because it treats URI
variables as opaque data to be fully encoded, while option 2 is useful only if
URI variables intentionally contain reserved characters.
Example usage using option 1:
The following example uses the first option:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -154,9 +170,12 @@ URI uri = UriComponentsBuilder.fromPath("/hotel list/{city}")
@@ -154,9 +170,12 @@ URI uri = UriComponentsBuilder.fromPath("/hotel list/{city}")
// Result is "/hotel%20list/New%20York?q=foo%2Bbar"
----
====
The above can be shortened by going directly to URI (which implies encoding):
You can shorten the preceding example by going directly to the URI (which implies encoding),
as the following example shows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -164,19 +183,24 @@ URI uri = UriComponentsBuilder.fromPath("/hotel list/{city}")
@@ -164,19 +183,24 @@ URI uri = UriComponentsBuilder.fromPath("/hotel list/{city}")
.queryParam("q", "{q}")
.build("New York", "foo+bar")
----
====
Or shorter further yet, with a full URI template:
You can shorten it further still with a full URI template, as the following example shows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
URI uri = UriComponentsBuilder.fromPath("/hotel list/{city}?q={q}")
.build("New York", "foo+bar")
----
====
The `WebClient` and the `RestTemplate` expand and encode URI templates internally through
the `UriBuilderFactory` strategy. Both can be configured with a custom strategy:
the `UriBuilderFactory` strategy. Both can be configured with a custom strategy.
as the following example shows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -191,22 +215,23 @@ the `UriBuilderFactory` strategy. Both can be configured with a custom strategy:
@@ -191,22 +215,23 @@ the `UriBuilderFactory` strategy. Both can be configured with a custom strategy:
Spring WebFlux includes a lightweight, functional programming model in which functions
Spring WebFlux includes a lightweight functional programming model in which functions
are used to route and handle requests and contracts are designed for immutability.
It is an alternative to the annotated-based programming model but otherwise running on
the same <<web-reactive.adoc#webflux-reactive-spring-web>> foundation
It is an alternative to the annotation-based programming model but otherwise runs on
the same <<web-reactive.adoc#webflux-reactive-spring-web>> foundation.
[[webflux-fn-overview]]
== Overview
An HTTP request is handled with a **`HandlerFunction`** that takes `ServerRequest` and
returns `Mono<ServerResponse>`, both of which are immutable contracts that offer JDK-8
friendly access to the HTTP request and response. `HandlerFunction` is the equivalent of
an `@RequestMapping` method in the annotation-based programming model.
An HTTP request is handled with a `HandlerFunction` that takes `ServerRequest` and
returns `Mono<ServerResponse>`, both of which are immutable contracts that offer
JDK 8-friendly access to the HTTP request and response. `HandlerFunction` is the equivalent of
a `@RequestMapping` method in the annotation-based programming model.
Requests are routed to a `HandlerFunction` with a **`RouterFunction`** that takes
Requests are routed to a `HandlerFunction` with a `RouterFunction` that takes
`ServerRequest` and returns `Mono<HandlerFunction>`. When a request is matched to a
particular route, the `HandlerFunction` mapped to the route is used. `RouterFunction` is
the equivalent of an `@RequestMapping` annotation.
the equivalent of a `@RequestMapping` annotation.
`RouterFunctions.route(RequestPredicate, HandlerFunction)` provides a router function
default implementation that can be used with a number of built-in request predicates.
For example:
default implementation that can be used with a number of built-in request predicates,
as the following example shows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -59,6 +59,7 @@ public class PersonHandler {
@@ -59,6 +59,7 @@ public class PersonHandler {
}
}
----
====
One way to run a `RouterFunction` is to turn it into an `HttpHandler` and install it
through one of the built-in <<web-reactive.adoc#webflux-httphandler,server adapters>>:
@ -66,96 +67,137 @@ through one of the built-in <<web-reactive.adoc#webflux-httphandler,server adapt
@@ -66,96 +67,137 @@ through one of the built-in <<web-reactive.adoc#webflux-httphandler,server adapt
[.small]#<<web.adoc#mvc-views-freemarker,Same in Spring MVC>>#
=== FreeMarker Configuration
[.small]#<<web.adoc#mvc-views-freemarker,Same as in Spring MVC>>#
FreeMarker 'Settings' and 'SharedVariables' can be passed directly to the FreeMarker
`Configuration` object managed by Spring by setting the appropriate bean properties on
You can pass FreeMarker 'Settings' and 'SharedVariables' directly to the FreeMarker
`Configuration` object (managed by Spring) by setting the appropriate bean properties on
the `FreeMarkerConfigurer` bean. The `freemarkerSettings` property requires a
`java.util.Properties` object and the `freemarkerVariables` property requires a
`java.util.Map`.
`java.util.Properties` object, and the `freemarkerVariables` property requires a
`java.util.Map`. The following example shows how to use a `FreeMarkerConfigurer`:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -108,53 +109,53 @@ the `FreeMarkerConfigurer` bean. The `freemarkerSettings` property requires a
@@ -108,53 +109,53 @@ the `FreeMarkerConfigurer` bean. The `freemarkerSettings` property requires a
}
}
----
====
See the FreeMarker documentation for details of settings and variables as they apply to
the `Configuration` object.
[[webflux-view-script]]
== Script Views
[.small]#<<web.adoc#mvc-view-script,Same in Spring MVC>>#
[.small]#<<web.adoc#mvc-view-script,Same as in Spring MVC>>#
The Spring Framework has a built-in integration for using Spring WebFlux with any
templating library that can run on top of the
https://www.jcp.org/en/jsr/detail?id=223[JSR-223] Java scripting engine. Below is a list
of templating libraries we've tested on different script engines:
TIP: The basic rule for integrating any other script engine is that it must implement the
`ScriptEngine` and `Invocable` interfaces.
====
[[webflux-view-script-dependencies]]
=== Requirements
[.small]#<<web.adoc#mvc-view-script-dependencies,Same in Spring MVC>>#
[.small]#<<web.adoc#mvc-view-script-dependencies,Same as in Spring MVC>>#
You need to have the script engine on your classpath:
You need to have the script engine on your classpath, the details of which vary by script engine:
* http://openjdk.java.net/projects/nashorn/[Nashorn] JavaScript engine is provided with
* The http://openjdk.java.net/projects/nashorn/[Nashorn] JavaScript engine is provided with
Java 8+. Using the latest update release available is highly recommended.
* http://jruby.org[JRuby] should be added as a dependency for Ruby support.
* http://www.jython.org[Jython] should be added as a dependency for Python support.
* `org.jetbrains.kotlin:kotlin-script-util` dependency and a `META-INF/services/javax.script.ScriptEngineFactory`
file containing a `org.jetbrains.kotlin.script.jsr223.KotlinJsr223JvmLocalScriptEngineFactory`
line should be added for Kotlin script support, see
https://github.com/sdeleuze/kotlin-script-templating[this example] for more details.
line should be added for Kotlin script support. See
https://github.com/sdeleuze/kotlin-script-templating[this example] for more detail.
You need to have the script templating library. One way to do that for Javascript is
through http://www.webjars.org/[WebJars].
@ -162,13 +163,14 @@ through http://www.webjars.org/[WebJars].
@@ -162,13 +163,14 @@ through http://www.webjars.org/[WebJars].
[[webflux-view-script-integrate]]
=== Script templates
[.small]#<<web.adoc#mvc-view-script-integrate,Same in Spring MVC>>#
=== Script Templates
[.small]#<<web.adoc#mvc-view-script-integrate,Same as in Spring MVC>>#
Declare a `ScriptTemplateConfigurer` bean in order to specify the script engine to use,
You can declare a `ScriptTemplateConfigurer` bean to specify the script engine to use,
the script files to load, what function to call to render templates, and so on.
Below is an example with Mustache templates and the Nashorn JavaScript engine:
The following example uses Mustache templates and the Nashorn JavaScript engine:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -192,24 +194,27 @@ Below is an example with Mustache templates and the Nashorn JavaScript engine:
@@ -192,24 +194,27 @@ Below is an example with Mustache templates and the Nashorn JavaScript engine:
}
}
----
====
The render function is called with the following parameters:
The `render` function is called with the following parameters:
that gives access to the application context, the locale, the template loader, and the
URL (since 5.0)
`Mustache.render()` is natively compatible with this signature, so you can call it directly.
If your templating technology requires some customization, you may provide a script that
If your templating technology requires some customization, you can provide a script that
implements a custom render function. For example, http://handlebarsjs.com[Handlerbars]
needs to compile templates before using them, and requires a
needs to compile templates before using them and requires a
http://en.wikipedia.org/wiki/Polyfill[polyfill] in order to emulate some
browser facilities not available in the server-side script engine.
The following example shows how to set a custom render function:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -233,28 +238,31 @@ browser facilities not available in the server-side script engine.
@@ -233,28 +238,31 @@ browser facilities not available in the server-side script engine.
}
}
----
[NOTE]
====
Setting the `sharedEngine` property to `false` is required when using non thread-safe
script engines with templating libraries not designed for concurrency, like Handlebars or
React running on Nashorn for example. In that case, Java 8u60 or greater is required due
NOTE: Setting the `sharedEngine` property to `false` is required when using non-thread-safe
script engines with templating libraries not designed for concurrency, such as Handlebars or
React running on Nashorn. In that case, Java 8u60 or greater is required, due
to https://bugs.openjdk.java.net/browse/JDK-8076099[this bug].
====
`polyfill.js` only defines the `window` object needed by Handlebars to run properly:
`polyfill.js` defines only the `window` object needed by Handlebars to run properly,
as the following snippet shows:
====
[source,javascript,indent=0]
[subs="verbatim,quotes"]
----
var window = {};
----
====
This basic `render.js` implementation compiles the template before using it. A production
ready implementation should also store and reused cached templates / pre-compiled templates.
ready implementation should also store and reused cached templates or pre-compiled templates.
This can be done on the script side, as well as any customization you need (managing
template engine configuration for example).
The following example shows how compile a template:
====
[source,javascript,indent=0]
[subs="verbatim,quotes"]
----
@ -263,34 +271,31 @@ template engine configuration for example).
@@ -263,34 +271,31 @@ template engine configuration for example).
return compiledTemplate(model);
}
----
====
Check out the Spring Framework unit tests,
https://github.com/spring-projects/spring-framework/tree/master/spring-webflux/src/test/java/org/springframework/web/reactive/result/view/script[java], and
https://github.com/spring-projects/spring-framework/tree/master/spring-webflux/src/test/java/org/springframework/web/reactive/result/view/script[Java], and
@ -7,14 +7,13 @@ using a functional-style API that exposes Reactor `Flux` and `Mono` types, see
@@ -7,14 +7,13 @@ using a functional-style API that exposes Reactor `Flux` and `Mono` types, see
<<web-reactive.adoc#webflux-codecs,codecs>> that WebFlux server applications use to work
with request and response content.
Internally `WebClient` delegates to an HTTP client library. By default it uses
Internally `WebClient` delegates to an HTTP client library. By default, it uses
https://github.com/reactor/reactor-netty[Reactor Netty], there is built-in support for
the Jetty https://github.com/jetty-project/jetty-reactive-httpclient[reactive HtpClient],
and others can be plugged in through a `ClientHttpConnector`.
[[webflux-client-builder]]
== Configuration
@ -23,22 +22,23 @@ The simplest way to create a `WebClient` is through one of the static factory me
@@ -23,22 +22,23 @@ The simplest way to create a `WebClient` is through one of the static factory me
* `WebClient.create()`
* `WebClient.create(String baseUrl)`
The above uses Reactor Netty `HttpClient` from "io.projectreactor.netty:reactor-netty"
with default settings and participates in global resources such for event loop threads and
a connection pool, see <<webflux-client-builder-reactor, Reactor Netty configuration>>.
The preceding methods use Reactor Netty `HttpClient` from `io.projectreactor.netty:reactor-netty`
with default settings and participates in global resources for event loop threads and
a connection pool. See <<webflux-client-builder-reactor, Reactor Netty configuration>>.
The `WebClient.Builder` can be used for access to further options:
You can use the `WebClient.Builder` for access to further options:
* `uriBuilderFactory` -- customized `UriBuilderFactory` to use as a base URL.
* `defaultHeader` -- headers for every request.
* `defaultCookie)` -- cookies for every request.
* `defaultRequest` -- `Consumer` to customize every request.
For example, to configure <<web-reactive.adoc#webflux-codecs,HTTP codecs>>:
The following example configures <<web-reactive.adoc#webflux-codecs,HTTP codecs>>:
====
[source,java,intent=0]
[subs="verbatim,quotes"]
----
@ -52,10 +52,12 @@ For example, to configure <<web-reactive.adoc#webflux-codecs,HTTP codecs>>:
@@ -52,10 +52,12 @@ For example, to configure <<web-reactive.adoc#webflux-codecs,HTTP codecs>>:
.exchangeStrategies(strategies)
.build();
----
====
Once built a `WebClient` instance is immutable. However, you can clone it, and build a
modified copy without affecting the original instance:
Once built, a `WebClient` instance is immutable. However, you can clone it and build a
modified copy without affecting the original instance, as the following example shows:
====
[source,java,intent=0]
[subs="verbatim,quotes"]
----
@ -69,14 +71,16 @@ modified copy without affecting the original instance:
@@ -69,14 +71,16 @@ modified copy without affecting the original instance:
// client2 has filterA, filterB, filterC, filterD
----
====
[[webflux-client-builder-reactor]]
=== Reactor Netty
To customize Reactor Netty settings:
You can customize Reactor Netty settings:
====
[source,java,intent=0]
[subs="verbatim,quotes"]
----
@ -85,18 +89,21 @@ To customize Reactor Netty settings:
@@ -85,18 +89,21 @@ To customize Reactor Netty settings:
By default `HttpClient` participates in the global Reactor Netty resources held in
By default, `HttpClient` participates in the global Reactor Netty resources held in
`reactor.netty.http.HttpResources`, including event loop threads and a connection pool.
This is the recommended mode since fixed, shared resources are preferred for event loop
This is the recommended mode, since fixed, shared resources are preferred for event loop
concurrency. In this mode global resources remain active until the process exits.
If the server is timed with the process, there is typically no need for an explicit
shutdown. However if the server can start or stop in-process, e.g. Spring MVC
application deployed as a WAR, you can declare a Spring-managed bean of type
`ReactorResourceFactory` with `useGlobalResources=true` (the default) to ensure the Reactor
Netty global resources are shut down when the Spring `ApplicationContext` is closed:
shutdown. However, if the server can start or stop in-process (for example, a Spring MVC
application deployed as a WAR), you can declare a Spring-managed bean of type
`ReactorResourceFactory` with `globalResources=true` (the default) to ensure that the Reactor
Netty global resources are shut down when the Spring `ApplicationContext` is closed,
as the following example shows:
====
[source,java,intent=0]
[subs="verbatim,quotes"]
----
@ -105,11 +112,13 @@ Netty global resources are shut down when the Spring `ApplicationContext` is clo
@@ -105,11 +112,13 @@ Netty global resources are shut down when the Spring `ApplicationContext` is clo
return new ReactorResourceFactory();
}
----
====
You may also choose not to participate in the global Reactor Netty resources. However keep
in mind in this mode the burden is on you to ensure all Reactor Netty client and server
instances use shared resources:
You can also choose not to participate in the global Reactor Netty resources. However,
in this mode, the burden is on you to ensure that all Reactor Netty client and server
instances use shared resources, as the following example shows:
====
[source,java,intent=0]
[subs="verbatim,quotes"]
----
@ -134,15 +143,18 @@ instances use shared resources:
@@ -134,15 +143,18 @@ instances use shared resources:
}
----
<1> Create resources independent of global ones.
<2> Use `ReactorClientHttpConnector` constructor with resource factory.
<2> Use the `ReactorClientHttpConnector` constructor with resource factory.
<3> Plug the connector into the `WebClient.Builder`.
====
[[webflux-client-builder-jetty]]
=== Jetty
To customize Jetty `HttpClient` settings:
The following example shows how to customize Jetty `HttpClient` settings:
====
[source,java,intent=0]
[subs="verbatim,quotes"]
----
@ -152,14 +164,16 @@ To customize Jetty `HttpClient` settings:
@@ -152,14 +164,16 @@ To customize Jetty `HttpClient` settings:
By default `HttpClient` creates its own resources (`Executor`, `ByteBufferPool`, `Scheduler`)
By default, `HttpClient` creates its own resources (`Executor`, `ByteBufferPool`, `Scheduler`),
which remain active until the process exits or `stop()` is called.
You can share resources between multiple intances of Jetty client (and server) and ensure the
You can share resources between multiple instances of the Jetty client (and server) and ensure that the
resources are shut down when the Spring `ApplicationContext` is closed by declaring a
Spring-managed bean of type `JettyResourceFactory`:
Spring-managed bean of type `JettyResourceFactory`, as the following example shows:
====
[source,java,intent=0]
[subs="verbatim,quotes"]
----
@ -183,16 +197,19 @@ Spring-managed bean of type `JettyResourceFactory`:
@@ -183,16 +197,19 @@ Spring-managed bean of type `JettyResourceFactory`:
----
<1> Create shared resources.
<2> Use `JettyClientHttpConnector` constructor with resource factory.
<2> Use the `JettyClientHttpConnector` constructor with resource factory.
<3> Plug the connector into the `WebClient.Builder`.
====
[[webflux-client-retrieve]]
== Retrieve
== Using the `retrieve` Method
The `retrieve()` method is the easiest way to get a response body and decode it:
The `retrieve()` method is the easiest way to get a response body and decode it.
The following example shows how to do so:
====
[source,java,intent=0]
[subs="verbatim,quotes"]
----
@ -203,9 +220,11 @@ The `retrieve()` method is the easiest way to get a response body and decode it:
@@ -203,9 +220,11 @@ The `retrieve()` method is the easiest way to get a response body and decode it:
.retrieve()
.bodyToMono(Person.class);
----
====
You can also get a stream of objects decoded from the response:
You can also get a stream of objects decoded from the response, as the following example shows:
====
[source,java,intent=0]
[subs="verbatim,quotes"]
----
@ -214,12 +233,15 @@ You can also get a stream of objects decoded from the response:
@@ -214,12 +233,15 @@ You can also get a stream of objects decoded from the response:
.retrieve()
.bodyToFlux(Quote.class);
----
====
By default, responses with 4xx or 5xx status codes result in an
`WebClientResponseException` or one of its HTTP status specific sub-classes such as
`WebClientResponseException` or one of its HTTP status specific sub-classes, such as
`WebClientResponseException.BadRequest`, `WebClientResponseException.NotFound`, and others.
You can also use the `onStatus` method to customize the resulting exception:
You can also use the `onStatus` method to customize the resulting exception,
as the following example shows:
====
[source,java,intent=0]
[subs="verbatim,quotes"]
----
@ -230,16 +252,17 @@ You can also use the `onStatus` method to customize the resulting exception:
@@ -230,16 +252,17 @@ You can also use the `onStatus` method to customize the resulting exception:
The `exchange()` method provides more control. The below example is equivalent
The `exchange()` method provides more control than the `retrieve` method. The following example is equivalent
to `retrieve()` but also provides access to the `ClientResponse`:
====
[source,java,intent=0]
[subs="verbatim,quotes"]
----
@ -248,9 +271,11 @@ to `retrieve()` but also provides access to the `ClientResponse`:
@@ -248,9 +271,11 @@ to `retrieve()` but also provides access to the `ClientResponse`:
At this level you can also create a full `ResponseEntity`:
At this level, you can also create a full `ResponseEntity`:
====
[source,java,intent=0]
[subs="verbatim,quotes"]
----
@ -259,27 +284,25 @@ At this level you can also create a full `ResponseEntity`:
@@ -259,27 +284,25 @@ At this level you can also create a full `ResponseEntity`:
Note that unlike `retrieve()`, with `exchange()` there are no automatic error signals for
Note that (unlike `retrieve()`), with `exchange()`, there are no automatic error signals for
4xx and 5xx responses. You have to check the status code and decide how to proceed.
[CAUTION]
====
When using `exchange()` you must always use any of the body or toEntity methods of
CAUTION: When you use `exchange()`, you must always use any of the `body` or `toEntity` methods of
`ClientResponse` to ensure resources are released and to avoid potential issues with HTTP
connection pooling. You can use `bodyToMono(Void.class)` if no response content is
expected. However keep in mind that if the response does have content, the connection
will be closed and will not be placed back in the pool.
====
expected. However, if the response does have content, the connection
is closed and is not placed back in the pool.
[[webflux-client-body]]
== Request body
== Request Body
The request body can be encoded from an Object:
The request body can be encoded from an `Object`, as the following example shows:
====
[source,java,intent=0]
[subs="verbatim,quotes"]
----
@ -292,9 +315,11 @@ The request body can be encoded from an Object:
@@ -292,9 +315,11 @@ The request body can be encoded from an Object:
.retrieve()
.bodyToMono(Void.class);
----
====
You can also have a stream of objects encoded:
You can also have a stream of objects be encoded, as the following example shows:
====
[source,java,intent=0]
[subs="verbatim,quotes"]
----
@ -307,9 +332,12 @@ You can also have a stream of objects encoded:
@@ -307,9 +332,12 @@ You can also have a stream of objects encoded:
.retrieve()
.bodyToMono(Void.class);
----
====
Or if you have the actual value, use the `syncBody` shortcut method:
Alternatively, if you have the actual value, you can use the `syncBody` shortcut method,
as the following example shows:
====
[source,java,intent=0]
[subs="verbatim,quotes"]
----
@ -322,16 +350,18 @@ Or if you have the actual value, use the `syncBody` shortcut method:
@@ -322,16 +350,18 @@ Or if you have the actual value, use the `syncBody` shortcut method:
.retrieve()
.bodyToMono(Void.class);
----
====
[[webflux-client-body-form]]
=== Form data
=== Form Data
To send form data, provide a `MultiValueMap<String, String>` as the body. Note that the
content is automatically set to `"application/x-www-form-urlencoded"` by the
`FormHttpMessageWriter`:
To send form data, you can provide a `MultiValueMap<String, String>` as the body. Note that the
content is automatically set to `application/x-www-form-urlencoded` by the
`FormHttpMessageWriter`. The following example shows how to use `MultiValueMap<String, String>`:
====
[source,java,intent=0]
[subs="verbatim,quotes"]
----
@ -343,9 +373,11 @@ content is automatically set to `"application/x-www-form-urlencoded"` by the
@@ -343,9 +373,11 @@ content is automatically set to `"application/x-www-form-urlencoded"` by the
.retrieve()
.bodyToMono(Void.class);
----
====
You can also supply form data in-line via `BodyInserters`:
You can also supply form data in-line by using `BodyInserters`, as the following example shows:
====
[source,java,intent=0]
[subs="verbatim,quotes"]
----
@ -357,16 +389,17 @@ You can also supply form data in-line via `BodyInserters`:
@@ -357,16 +389,17 @@ You can also supply form data in-line via `BodyInserters`:
.retrieve()
.bodyToMono(Void.class);
----
====
[[webflux-client-body-multipart]]
=== Multipart data
=== Multipart Data
To send multipart data, you need to provide a `MultiValueMap<String, ?>` whose values are
either Objects representing part content, or `HttpEntity` representing the content and
either `Object` instances that represent part content or `HttpEntity` instances that represent the content and
headers for a part. `MultipartBodyBuilder` provides a convenient API to prepare a
multipart request:
multipart request. The following example shows how to create a `MultiValueMap<String, ?>`:
MultiValueMap<String, HttpEntity<?>> parts = builder.build();
----
In most cases you do not have to specify the `Content-Type` for each part. The content
type is determined automatically based on the `HttpMessageWriter` chosen to serialize it,
or in the case of a `Resource` based on the file extension. If necessary you can
explicitly provide the `MediaType` to use for each part through one fo the overloaded
In most cases, you do not have to specify the `Content-Type` for each part. The content
type is determined automatically based on the `HttpMessageWriter` chosen to serialize it
or, in the case of a `Resource`, based on the file extension. If necessary, you can
explicitly provide the `MediaType` to use for each part through one of the overloaded
builder `part` methods.
Once a `MultiValueMap` is prepared, the easiest way to pass it to the the `WebClient` is
through the `syncBody` method:
through the `syncBody` method, as the following example shows:
====
[source,java,intent=0]
[subs="verbatim,quotes"]
----
@ -399,15 +433,17 @@ through the `syncBody` method:
@@ -399,15 +433,17 @@ through the `syncBody` method:
.retrieve()
.bodyToMono(Void.class);
----
====
If the `MultiValueMap` contains at least one non-String value, which could also be
represent regular form data (i.e. "application/x-www-form-urlencoded"), you don't have to
set the `Content-Type` to "multipart/form-data". This is always the case when using
`MultipartBodyBuilder` which ensures an `HttpEntity` wrapper.
If the `MultiValueMap` contains at least one non-`String` value, which could also
represent regular form data (that is, `application/x-www-form-urlencoded`), you need not
set the `Content-Type` to `multipart/form-data`. This is always the case when using
`MultipartBodyBuilder`, which ensures an `HttpEntity` wrapper.
As an alternative to `MultipartBodyBuilder`, you can also provide multipart content,
inline-style, through the built-in `BodyInserters`. For example:
inline-style, through the built-in `BodyInserters`, as the following example shows:
====
[source,java,intent=0]
[subs="verbatim,quotes"]
----
@ -419,7 +455,7 @@ inline-style, through the built-in `BodyInserters`. For example:
@@ -419,7 +455,7 @@ inline-style, through the built-in `BodyInserters`. For example:
.retrieve()
.bodyToMono(Void.class);
----
====
@ -427,8 +463,9 @@ inline-style, through the built-in `BodyInserters`. For example:
@@ -427,8 +463,9 @@ inline-style, through the built-in `BodyInserters`. For example:
== Client Filters
You can register a client filter (`ExchangeFilterFunction`) through the `WebClient.Builder`
in order to intercept and/or modify requests:
in order to intercept and modify requests, as the following example shows:
[.small]#<<web.adoc#websocket,Same in Servlet stack>>#
[.small]#<<web.adoc#websocket,Same as in the Servlet stack>>#
This part of the reference documentation covers support for Reactive stack, WebSocket
This part of the reference documentation covers support for reactive-stack WebSocket
messaging.
include::websocket-intro.adoc[leveloffset=+1]
[[webflux-websocket-server]]
== WebSocket API
[.small]#<<web.adoc#websocket-server,Same in Servlet stack>>#
[.small]#<<web.adoc#websocket-server,Same as in the Servlet stack>>#
The Spring Framework provides a WebSocket API that can be used to write client and
serverside applications that handle WebSocket messages.
The Spring Framework provides a WebSocket API that you can use to write client- and
server-side applications that handle WebSocket messages.
[[webflux-websocket-server-handler]]
=== Server
[.small]#<<web.adoc#websocket-server-handler,Same in Servlet stack>>#
[.small]#<<web.adoc#websocket-server-handler,Same as in the Servlet stack>>#
To create a WebSocket server, first create a `WebSocketHandler`:
To create a WebSocket server, you can first create a `WebSocketHandler`.
The following example shows how to do so:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -39,9 +42,11 @@ To create a WebSocket server, first create a `WebSocketHandler`:
@@ -39,9 +42,11 @@ To create a WebSocket server, first create a `WebSocketHandler`:
}
}
----
====
Then map it to a URL and add a `WebSocketHandlerAdapter`:
Then you can map it to a URL and add a `WebSocketHandlerAdapter`, as the following example shows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -65,22 +70,24 @@ Then map it to a URL and add a `WebSocketHandlerAdapter`:
@@ -65,22 +70,24 @@ Then map it to a URL and add a `WebSocketHandlerAdapter`:
}
}
----
====
[[webflux-websockethandler]]
=== WebSocketHandler
=== Using `WebSocketHandler`
The `handle` method of `WebSocketHandler` takes `WebSocketSession` and returns `Mono<Void>`
to indicate when application handling of the session is complete. The session is handled
through two streams, one for inbound and one for outbound messages:
through two streams, one for inbound and one for outbound messages. The following table
describes the two methods that handle the streams:
[options="header"]
|===
| WebSocketSession method | Description
| `WebSocketSession` method | Description
| `Flux<WebSocketMessage> receive()`
| Provides access to the inbound message stream, and completes when the connection is closed.
| Provides access to the inbound message stream and completes when the connection is closed.
| `Mono<Void> send(Publisher<WebSocketMessage>)`
| Takes a source for outgoing messages, writes the messages, and returns a `Mono<Void>` that
@ -88,21 +95,23 @@ through two streams, one for inbound and one for outbound messages:
@@ -88,21 +95,23 @@ through two streams, one for inbound and one for outbound messages:
|===
A `WebSocketHandler` must compose the inbound and outbound streams into a unified flow, and
A `WebSocketHandler` must compose the inbound and outbound streams into a unified flow and
return a `Mono<Void>` that reflects the completion of that flow. Depending on application
requirements, the unified flow completes when:
* Either inbound or outbound message streams complete.
* Inbound stream completes (i.e. connection closed), while outbound is infinite.
* At a chosen point through the `close` method of `WebSocketSession`.
* Either the inbound or the outbound message stream completes.
* The inbound stream completes (that is, the connection closed), while the outbound stream is infinite.
* At a chosen point, through the `close` method of `WebSocketSession`.
When inbound and outbound message streams are composed together, there is no need to
check if the connection is open, since Reactive Streams signals will terminate activity.
The inbound stream receives a completion/error signal, and the outbound stream receives
check if the connection is open, since Reactive Streams signals terminate activity.
The inbound stream receives a completion or error signal, and the outbound stream
receives a cancellation signal.
The most basic implementation of a handler is one that handles the inbound stream:
The most basic implementation of a handler is one that handles the inbound stream. The
following example shows such an implementation:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -121,21 +130,20 @@ class ExampleHandler implements WebSocketHandler {
@@ -121,21 +130,20 @@ class ExampleHandler implements WebSocketHandler {
}
}
----
<1> Access stream of inbound messages.
<1> Access the stream of inbound messages.
<2> Do something with each message.
<3> Perform nested async operation using message content.
<4> Return `Mono<Void>` that completes when receiving completes.
[TIP]
<3> Perform nested asynchronous operations that use the message content.
<4> Return a `Mono<Void>` that completes when receiving completes.
====
For nested, asynchronous operations, you may need to call `message.retain()` on underlying
servers that use pooled data buffers (e.g. Netty), or otherwise the data buffer may be
released before you've had a chance to read the data. For more background see
TIP: For nested, asynchronous operations, you may need to call `message.retain()` on underlying
servers that use pooled data buffers (for example, Netty). Otherwise, the data buffer may be
released before you have had a chance to read the data. For more background, see
<<core.adoc#databuffers,Data Buffers and Codecs>>.
====
The below implementation combines the inbound with the outbound streams:
The following implementation combines the inbound and outbound streams:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -157,12 +165,15 @@ class ExampleHandler implements WebSocketHandler {
@@ -157,12 +165,15 @@ class ExampleHandler implements WebSocketHandler {
}
}
----
<1> Handle inbound message stream.
<2> Create outbound message, producing a combined flow.
<3> Return `Mono<Void>` that doesn't complete while we continue to receive.
<1> Handle the inbound message stream.
<2> Create the outbound message, producing a combined flow.
<3> Return a `Mono<Void>` that does not complete while we continue to receive.
====
Inbound and outbound streams can be independent, and joined only for completion:
Inbound and outbound streams can be independent and be joined only for completion,
as the following example shows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -189,17 +200,18 @@ class ExampleHandler implements WebSocketHandler {
@@ -189,17 +200,18 @@ class ExampleHandler implements WebSocketHandler {
----
<1> Handle inbound message stream.
<2> Send outgoing messages.
<3> Join the streams and return `Mono<Void>` that completes when _either_ stream ends.
<3> Join the streams and return a `Mono<Void>` that completes when either stream ends.
====
[[webflux-websocket-server-handshake]]
=== Handshake
[.small]#<<web.adoc#websocket-server-handshake,Same in Servlet stack>>#
[.small]#<<web.adoc#websocket-server-handshake,Same as in the Servlet stack>>#
`WebSocketHandlerAdapter` delegates to a `WebSocketService`. By default that's an instance
`WebSocketHandlerAdapter` delegates to a `WebSocketService`. By default, that is an instance
of `HandshakeWebSocketService`, which performs basic checks on the WebSocket request and
then uses `RequestUpgradeStrategy` for the server in use. Currently there is built-in
then uses `RequestUpgradeStrategy` for the server in use. Currently, there is built-in
support for Reactor Netty, Tomcat, Jetty, and Undertow.
`HandshakeWebSocketService` exposes a `sessionAttributePredicate` property that allows
@ -208,15 +220,15 @@ into the attributes of the `WebSocketSession`.
@@ -208,15 +220,15 @@ into the attributes of the `WebSocketSession`.
[[webflux-websocket-server-config]]
=== Server config
[.small]#<<web.adoc#websocket-server-runtime-configuration,Same in Servlet stack>>#
=== Server Configation
[.small]#<<web.adoc#websocket-server-runtime-configuration,Same as in the Servlet stack>>#
The `RequestUpgradeStrategy` for each server exposes WebSocket-related configuration
options available for the underlying WebSocket engine. Below is an example of setting
options available for the underlying WebSocket engine. The following example sets
WebSocket options when running on Tomcat:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -236,21 +248,22 @@ WebSocket options when running on Tomcat:
@@ -236,21 +248,22 @@ WebSocket options when running on Tomcat:
}
}
----
====
Check the upgrade strategy for your server to see what options are available. Currently
Check the upgrade strategy for your server to see what options are available. Currently,
only Tomcat and Jetty expose such options.
[[webflux-websocket-server-cors]]
=== CORS
[.small]#<<web.adoc#websocket-server-allowed-origins,Same in Servlet stack>>#
[.small]#<<web.adoc#websocket-server-allowed-origins,Same as in the Servlet stack>>#
The easiest way to configure CORS and restrict access to a WebSocket endpoint is to
have your `WebSocketHandler` implement `CorsConfigurationSource` and return a
`CorsConfiguraiton` with allowed origins, headers, etc. If for any reason you can't do
`CorsConfiguraiton` with allowed origins, headers, and other details. If you cannot do
that, you can also set the `corsConfigurations` property on the `SimpleUrlHandler` to
specify CORS settings by URL pattern. If both are specified they're combined via the
specify CORS settings by URL pattern. If both are specified, they are combined by using the
`combine` method on `CorsConfiguration`.
@ -259,18 +272,16 @@ specify CORS settings by URL pattern. If both are specified they're combined via
@@ -259,18 +272,16 @@ specify CORS settings by URL pattern. If both are specified they're combined via
=== Client
Spring WebFlux provides a `WebSocketClient` abstraction with implementations for
Reactor Netty, Tomcat, Jetty, Undertow, and standard Java (i.e. JSR-356).
Reactor Netty, Tomcat, Jetty, Undertow, and standard Java (that is, JSR-356).
[NOTE]
====
The Tomcat client is effectively an extension of the standard Java one with some extra
functionality in the `WebSocketSession` handling taking advantage of Tomcat specific
NOTE: The Tomcat client is effectively an extension of the standard Java one with some extra
functionality in the `WebSocketSession` handling to take advantage of the Tomcat-specific
API to suspend receiving messages for back pressure.
====
To start a WebSocket session, create an instance of the client and use its `execute`
To start a WebSocket session, you can create an instance of the client and use its `execute`
@ -5,40 +5,35 @@ This section describes options for client-side access to REST endpoints.
@@ -5,40 +5,35 @@ This section describes options for client-side access to REST endpoints.
[[webmvc-resttemplate]]
== RestTemplate
== Using `RestTemplate`
`RestTemplate` is a synchronous client to perform HTTP requests. It is the original
Spring REST client, exposing a simple, template method API over underlying HTTP client
Spring REST client and exposes a simple, template-method API over underlying HTTP client
libraries.
[NOTE]
====
As of 5.0, the non-blocking, reactive `WebClient` offers a modern alternative to the
`RestTemplate` with efficient support for both sync and async, as well as streaming
NOTE: As of 5.0, the non-blocking, reactive `WebClient` offers a modern alternative to the
`RestTemplate`, with efficient support for both synchronous and asynchronous, as well as streaming
scenarios. The `RestTemplate` will be deprecated in a future version and will not have
major new features added going forward.
====
See <<integration.adoc#rest-client-access,RestTemplate>> for details.
See <<integration.adoc#rest-client-access,REST Endpoints>> for details.
[[webmvc-webclient]]
== WebClient
== Using `WebClient`
`WebClient` is a non-blocking, reactive client to perform HTTP requests. It was
introduced in 5.0 and offers a modern alternative to the `RestTemplate` with efficient
introduced in 5.0 and offers a modern alternative to the `RestTemplate`, with efficient
support for both synchronous and asynchronous, as well as streaming scenarios.
In contrast to the `RestTemplate`, the `WebClient` supports the following:
In contrast to `RestTemplate`, `WebClient` supports the following:
* Non-blocking I/O.
* Reactive Streams back pressure.
* High concurrency with less hardware resources.
* Functional-style, fluent API taking advantage of Java 8 lambdas.
* High concurrency with fewer hardware resources.
* Functional-style, fluent API that takes advantage of Java 8 lambdas.
* Synchronous and asynchronous interactions.
* Streaming up to or streaming down from a server.
To learn more from the source or make advanced customizations, check:
To learn more from the source or make advanced customizations, check the code behind:
* `CorsConfiguration`
* `CorsProcessor`, `DefaultCorsProcessor`
@ -71,14 +72,15 @@ To learn more from the source or make advanced customizations, check:
@@ -71,14 +72,15 @@ To learn more from the source or make advanced customizations, check:
[[mvc-cors-controller]]
== @CrossOrigin
[.small]#<<web-reactive.adoc#webflux-cors-controller,Same in Spring WebFlux>>#
== Using `@CrossOrigin`
[.small]#<<web-reactive.adoc#webflux-cors-controller,Same as in Spring WebFlux>>#
The {api-spring-framework}/web/bind/annotation/CrossOrigin.html[`@CrossOrigin`]
annotation enables cross-origin requests on annotated controller methods:
annotation enables cross-origin requests on annotated controller methods,
as the following example shows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -98,19 +100,24 @@ public class AccountController {
@@ -98,19 +100,24 @@ public class AccountController {
}
}
----
====
By default `@CrossOrigin` allows:
By default, `@CrossOrigin` allows:
* All origins.
* All headers.
* All HTTP methods to which the controller method is mapped.
* `allowedCredentials` is not enabled by default since that establishes a trust level
that exposes sensitive user-specific information such as cookies and CSRF tokens, and
`allowedCredentials` is not enabled by default, since that establishes a trust level
that exposes sensitive user-specific information (such as cookies and CSRF tokens) and
should only be used where appropriate.
* `maxAge` is set to 30 minutes.
`@CrossOrigin` is supported at the class level too and inherited by all methods:
`maxAge` is set to 30 minutes.
`@CrossOrigin` is supported at the class level, too, and is inherited by all methods,
as the following example shows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -130,9 +137,12 @@ public class AccountController {
@@ -130,9 +137,12 @@ public class AccountController {
}
}
----
====
`CrossOrigin` can be used at both class and method-level:
You can use `@CrossOrigin` at both the class level and the method level,
as the following example shows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -153,38 +163,43 @@ public class AccountController {
@@ -153,38 +163,43 @@ public class AccountController {
}
}
----
====
[[mvc-cors-global]]
== Global Config
[.small]#<<web-reactive.adoc#webflux-cors-global,Same in Spring WebFlux>>#
== Global Configuration
[.small]#<<web-reactive.adoc#webflux-cors-global,Same as in Spring WebFlux>>#
In addition to fine-grained, controller method level configuration you'll probably want to
define some global CORS configuration too. You can set URL-based `CorsConfiguration`
mappings individually on any `HandlerMapping`. Most applications however will use the
MVC Java config or the MVC XNM namespace to do that.
In addition to fine-grained, controller method level configuration, you probably want to
define some global CORS configuration, too. You can set URL-based `CorsConfiguration`
mappings individually on any `HandlerMapping`. Most applications, however, use the
MVC Java configuration or the MVC XNM namespace to do that.
By default global configuration enables the following:
By default, global configuration enables the following:
* All origins.
* All headers.
* `GET`, `HEAD`, and `POST` methods.
* `allowedCredentials` is not enabled by default since that establishes a trust level
that exposes sensitive user-specific information such as cookies and CSRF tokens, and
`allowedCredentials` is not enabled by default, since that establishes a trust level
that exposes sensitive user-specific information (such as cookies and CSRF tokens) and
should only be used where appropriate.
* `maxAge` is set to 30 minutes.
`maxAge` is set to 30 minutes.
[[mvc-cors-global-java]]
=== Java Config
[.small]#<<web-reactive.adoc#webflux-cors-global,Same in Spring WebFlux>>#
=== Java Configuration
[.small]#<<web-reactive.adoc#webflux-cors-global,Same as in Spring WebFlux>>#
To enable CORS in the MVC Java config, use the `CorsRegistry` callback:
To enable CORS in the MVC Java config, you can use the `CorsRegistry` callback,
as the following example shows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -206,14 +221,17 @@ public class WebConfig implements WebMvcConfigurer {
@@ -206,14 +221,17 @@ public class WebConfig implements WebMvcConfigurer {
}
}
----
====
[[mvc-cors-global-xml]]
=== XML Config
=== XML Configuration
To enable CORS in the XML namespace, use the `<mvc:cors>` element:
To enable CORS in the XML namespace, you can use the `<mvc:cors>` element,
as the following example shows:
====
[source,xml,indent=0]
[subs="verbatim"]
----
@ -231,28 +249,26 @@ To enable CORS in the XML namespace, use the `<mvc:cors>` element:
@@ -231,28 +249,26 @@ To enable CORS in the XML namespace, use the `<mvc:cors>` element:
</mvc:cors>
----
====
[[mvc-cors-filter]]
== CORS Filter
[.small]#<<web-reactive.adoc#webflux-cors-webfilter,Same in Spring WebFlux>>#
[.small]#<<web-reactive.adoc#webflux-cors-webfilter,Same as in Spring WebFlux>>#