Edit the Web chapter of the reference documentation

I edited for spelling, punctuation, grammar, usage,
and corporate voice. I also added links and cross-references.
This commit is contained in:
Jay Bryant 2018-09-17 09:36:43 -05:00 committed by Brian Clozel
parent b29a278b2a
commit 00a3afcda8
17 changed files with 4882 additions and 4061 deletions

View File

@ -7,12 +7,12 @@
:tabsize: 4
:docinfo1:
This part of the documentation covers support for reactive stack, web applications built on a
This part of the documentation covers support for reactive-stack web applications built on a
http://www.reactive-streams.org/[Reactive Streams] API to run on non-blocking
servers such as Netty, Undertow, and Servlet 3.1+ containers. Individual chapters cover
servers, such as Netty, Undertow, and Servlet 3.1+ containers. Individual chapters cover
the <<webflux,Spring WebFlux>> framework,
the reactive <<webflux-client,WebClient>>, support for <<webflux-test>>,
and <<webflux-reactive-libraries>>. For Servlet stack, web applications, please see
the reactive <<webflux-client,`WebClient`>>, support for <<webflux-test, testing>>,
and <<webflux-reactive-libraries, reactive libraries>>. For Servlet-stack web applications, see
<<web.adoc#spring-web,Web on Servlet Stack>>.
include::web/webflux.adoc[leveloffset=+1]
@ -29,19 +29,18 @@ include::web/webflux-websocket.adoc[leveloffset=+1]
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.
== 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.
====

View File

@ -7,10 +7,10 @@
:tabsize: 4
:docinfo1:
This part of the documentation covers support for Servlet stack, web applications built on the
This part of the documentation covers support for Servlet-stack web applications built on the
Servlet API and deployed to Servlet containers. Individual chapters include <<mvc,Spring MVC>>,
<<mvc-view,View Technologies>>, <<mvc-cors,CORS Support>>, and <<websocket,WebSocket Support>>.
For reactive stack, web applications, go to <<web-reactive.adoc#spring-web-reactive,Web on Reactive Stack>>.
For reactive-stack web applications, see <<web-reactive.adoc#spring-web-reactive,Web on Reactive Stack>>.
include::web/webmvc.adoc[leveloffset=+1]
@ -21,4 +21,3 @@ include::web/webmvc-test.adoc[leveloffset=+1]
include::web/websocket.adoc[leveloffset=+1]
include::web/integration.adoc[leveloffset=+1]

View File

@ -1,53 +1,47 @@
[[web-integration]]
= Other Web Frameworks
[[intro]]
== Introduction
This chapter details Spring's integration with third party web frameworks.
One of the core value propositions of the Spring Framework is that of enabling
__choice__. In a general sense, Spring does not force one to use or buy into any
_choice_. In a general sense, Spring does not force you to use or buy into any
particular architecture, technology, or methodology (although it certainly recommends
some over others). This freedom to pick and choose the architecture, technology, or
methodology that is most relevant to a developer and their development team is
arguably most evident in the web area, where Spring provides its own web framework
(<<mvc,Spring MVC>>), while at the same time providing integration with a number of
(<<mvc,Spring MVC>>) while, at the same time, providing integration with a number of
popular third party web frameworks.
[[web-integration-common]]
== Common config
== Common Configuration
Before diving into the integration specifics of each supported web framework, let us
first take a look at the Spring configuration that is __not__ specific to any one web
first take a look at the Spring configuration that is not specific to any one web
framework. (This section is equally applicable to Spring's own web framework, Spring
MVC.)
One of the concepts (for want of a better word) espoused by (Spring's) lightweight
application model is that of a layered architecture. Remember that in a 'classic'
layered architecture, the web layer is but one of many layers; it serves as one of the
entry points into a server side application and it delegates to service objects
(facades) defined in a service layer to satisfy business specific (and
One of the concepts (for want of a better word) espoused by Spring's lightweight
application model is that of a layered architecture. Remember that in a "`classic`"
layered architecture, the web layer is but one of many layers. It serves as one of the
entry points into a server-side application, and it delegates to service objects
(facades) that are defined in a service layer to satisfy business-specific (and
presentation-technology agnostic) use cases. In Spring, these service objects, any other
business-specific objects, data access objects, etc. exist in a distinct 'business
context', which contains __no__ web or presentation layer objects (presentation objects
such as Spring MVC controllers are typically configured in a distinct 'presentation
context'). This section details how one configures a Spring container (a
`WebApplicationContext`) that contains all of the 'business beans' in one's application.
business-specific objects, data-access objects, and others exist in a distinct "`business
context`", which contains no web or presentation layer objects (presentation objects
,such as Spring MVC controllers, are typically configured in a distinct "`presentation
context`"). This section details how you can configure a Spring container (a
`WebApplicationContext`) that contains all of the 'business beans' in your application.
On to specifics: all that one need do is to declare a
Moving on to specifics, all you one need to do is declare a
{api-spring-framework}/web/context/ContextLoaderListener.html[`ContextLoaderListener`]
in the standard Java EE servlet `web.xml` file of one's web application, and add a
in the standard Java EE servlet `web.xml` file of your web application and add a
`contextConfigLocation`<context-param/> section (in the same file) that defines which
set of Spring XML configuration files to load.
Find below the <listener/> configuration:
Consider the following `<listener/>` configuration:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@ -55,9 +49,11 @@ Find below the <listener/> configuration:
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
----
====
Find below the <context-param/> configuration:
Further consider the following `<context-param/>` configuration:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@ -66,30 +62,35 @@ Find below the <context-param/> configuration:
<param-value>/WEB-INF/applicationContext*.xml</param-value>
</context-param>
----
====
If you don't specify the `contextConfigLocation` context parameter, the
`ContextLoaderListener` will look for a file called `/WEB-INF/applicationContext.xml` to
If you do not specify the `contextConfigLocation` context parameter, the
`ContextLoaderListener` looks for a file called `/WEB-INF/applicationContext.xml` to
load. Once the context files are loaded, Spring creates a
{api-spring-framework}/web/context/WebApplicationContext.html[`WebApplicationContext`]
object based on the bean definitions and stores it in the `ServletContext` of the web
application.
All Java web frameworks are built on top of the Servlet API, and so one can use the
following code snippet to get access to this 'business context' `ApplicationContext`
All Java web frameworks are built on top of the Servlet API, so you can use the
following code snippet to get access to this "`business context`" `ApplicationContext`
created by the `ContextLoaderListener`.
The following example shows how to get the `WebApplicationContext`:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
WebApplicationContext ctx = WebApplicationContextUtils.getWebApplicationContext(servletContext);
----
====
The
{api-spring-framework}/web/context/support/WebApplicationContextUtils.html[`WebApplicationContextUtils`]
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.
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.
[[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:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@ -148,33 +148,39 @@ __faces-context.xml__ file:
</application>
</faces-config>
----
====
[[jsf-facescontextutils]]
=== FacesContextUtils
A custom `VariableResolver` works well when mapping one's properties to beans
in __faces-config.xml__, but at times one may need to grab a bean explicitly. The
=== Using `FacesContextUtils`
A custom `VariableResolver` works well when mapping your properties to beans
in `faces-config.xml`, but, at times, you may need to explicitly grab a bean. The
{api-spring-framework}/web/jsf/FacesContextUtils.html[`FacesContextUtils`]
class makes this easy. It is similar to `WebApplicationContextUtils`, except that it
takes a `FacesContext` parameter rather than a `ServletContext` parameter.
The following example shows how to use `FacesContextUtils`:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
ApplicationContext ctx = FacesContextUtils.getWebApplicationContext(FacesContext.getCurrentInstance());
----
====
[[struts]]
== Apache Struts 2.x
Invented by Craig McClanahan, http://struts.apache.org[Struts] is an open source project
Invented by Craig McClanahan, http://struts.apache.org[Struts] is an open-source project
hosted by the Apache Software Foundation. At the time, it greatly simplified the
JSP/Servlet programming paradigm and won over many developers who were using proprietary
frameworks. It simplified the programming model, it was open source (and thus free as in
beer), and it had a large community, which allowed the project to grow and become popular
frameworks. It simplified the programming model, it was open source (and thus free, as in
beer), and it had a large community, which let the project grow and become popular
among Java web developers.
Check out the Struts
@ -183,28 +189,25 @@ built-in Spring integration shipped with Struts.
[[tapestry]]
== Tapestry 5.x
From the http://tapestry.apache.org/[Tapestry homepage]:
Tapestry is a "__Component oriented framework for creating dynamic, robust,
highly scalable web applications in Java.__"
http://tapestry.apache.org/[Tapestry] is a ""Component oriented framework for creating dynamic, robust,
highly scalable web applications in Java.""
While Spring has its own <<mvc,powerful web layer>>, there are a number of unique
advantages to building an enterprise Java application using a combination of Tapestry
advantages to building an enterprise Java application by using a combination of Tapestry
for the web user interface and the Spring container for the lower layers.
For more information, check out Tapestry's dedicated
For more information, see Tapestry's dedicated
https://tapestry.apache.org/integrating-with-spring-framework.html[integration module for
Spring].
[[web-integration-resources]]
== Further Resources
Find below links to further resources about the various web frameworks described in this
The following links go to further resources about the various web frameworks described in this
chapter.
* The http://www.oracle.com/technetwork/java/javaee/javaserverfaces-139869.html[JSF] homepage

View File

@ -3,8 +3,9 @@
= UriComponents
[.small]#Spring MVC and Spring WebFlux#
`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 @@
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`
.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):
.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:
.fromUriString("http://example.com/hotels/{hotel}?q={q}")
.build("Westin", "123");
----
====
[[web-uribuilder]]
= UriBuilder
[.small]#Spring MVC and Spring WebFlux#
<<web-uricomponents,UriComponentsBuilder>> implements `UriBuilder`. A `UriBuilder` in turn
can be created with a `UriBuilderFactory`. Together `UriBuilderFactory` and `UriBuilder`
<<web-uricomponents,`UriComponentsBuilder`>> implements `UriBuilder`. You can create a `UriBuilder`, in turn,
with a `UriBuilderFactory`. Together, `UriBuilderFactory` and `UriBuilder`
provide a pluggable mechanism to build URIs from URI templates, based on shared
configuration such as a base url, encoding preferences, and others.
configuration, such as a base URL, encoding preferences, and other details.
The `RestTemplate` and the `WebClient` can be configured with a `UriBuilderFactory`
You can configure `RestTemplate` and `WebClient` with a `UriBuilderFactory`
to customize the preparation of URIs. `DefaultUriBuilderFactory` is a default
implementation of `UriBuilderFactory` that uses `UriComponentsBuilder` internally and
exposes shared configuration options.
`RestTemplate` example:
The following example shows how to configure a `RestTemplate`:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -85,9 +97,11 @@ exposes shared configuration options.
RestTemplate restTemplate = new RestTemplate();
restTemplate.setUriTemplateHandler(factory);
----
====
`WebClient` example:
The following example configures a `WebClient`:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -99,11 +113,13 @@ exposes shared configuration options.
WebClient client = WebClient.builder().uriBuilderFactory(factory).build();
----
====
In addition `DefaultUriBuilderFactory` can also be used directly. It is similar to using
`UriComponentsBuilder` but instead of static factory methods, it is an actual instance
that holds configuration and preferences:
In addition, you can also use `DefaultUriBuilderFactory` directly. It is similar to using
`UriComponentsBuilder` but, instead of static factory methods, it is an actual instance
that holds configuration and preferences, as the following example shows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -114,35 +130,35 @@ that holds configuration and preferences:
.queryParam("q", "{q}")
.build("Westin", "123");
----
====
[[web-uri-encoding]]
= URI Encoding
[.small]#Spring MVC and Spring WebFlux#
`UriComponentsBuilder` exposes encoding options at 2 levels:
`UriComponentsBuilder` exposes encoding options at two levels:
. {api-spring-framework}/web/util/UriComponentsBuilder.html#encode--[UriComponentsBuilder#encode()] -
pre-encodes the URI template first, then strictly encodes URI variables when expanded.
. {api-spring-framework}/web/util/UriComponents.html#encode--[UriComponents#encode()] -
encodes URI components _after_ URI variables are expanded.
* {api-spring-framework}/web/util/UriComponentsBuilder.html#encode--[UriComponentsBuilder#encode()]:
Pre-encodes the URI template first and then strictly encodes URI variables when expanded.
* {api-spring-framework}/web/util/UriComponents.html#encode--[UriComponents#encode()]:
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}")
// 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}")
.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:
// Customize the WebClient..
WebClient client = WebClient.builder().uriBuilderFactory(factory).build();
----
====
The `DefaultUriBuilderFactory` implementation uses `UriComponentsBuilder` internally to
expand and encode URI templates. As a factory it provides a single place to configure
the approach to encoding based on one of the below encoding modes:
expand and encode URI templates. As a factory, it provides a single place to configure
the approach to encoding, based on one of the below encoding modes:
* `TEMPLATE_AND_VALUES` -- uses `UriComponentsBuilder#encode()`, corresponding to
option 1 above, to pre-encode the URI template and strictly encode URI variables when
* `TEMPLATE_AND_VALUES`: Uses `UriComponentsBuilder#encode()`, corresponding to
the first option in the earlier list, to pre-encode the URI template and strictly encode URI variables when
expanded.
* `VALUES_ONLY` -- does not encode the URI template and instead applies strict encoding
to URI variables via `UriUtils#encodeUriUriVariables` prior to expanding them into the
* `VALUES_ONLY`: Does not encode the URI template and, instead, applies strict encoding
to URI variables through `UriUtils#encodeUriUriVariables` prior to expanding them into the
template.
* `URI_COMPONENTS` -- uses `UriComponents#encode()`, corresponding to option 2 above, to
* `URI_COMPONENTS`: Uses `UriComponents#encode()`, corresponding to the second option in the earlier list, to
encode URI component value _after_ URI variables are expanded.
* `NONE` -- no encoding is applied.
* `NONE`: No encoding is applied.
Out of the box the `RestTemplate` is set to `EncodingMode.URI_COMPONENTS` for historic
The `RestTemplate` is set to `EncodingMode.URI_COMPONENTS` for historic
reasons and for backwards compatibility. The `WebClient` relies on the default value
in `DefaultUriBuilderFactory` which was changed from `EncodingMode.URI_COMPONENTS` in
5.0.x to `EncodingMode.TEMPLATE_AND_VALUES` in 5.1.
in `DefaultUriBuilderFactory`, which was changed from `EncodingMode.URI_COMPONENTS` in
5.0.x to `EncodingMode.TEMPLATE_AND_VALUES` in 5.1.

View File

@ -1,84 +1,86 @@
[[webflux-cors]]
= CORS
[.small]#<<web.adoc#mvc-cors,Same in Spring MVC>>#
[.small]#<<web.adoc#mvc-cors,Same as in Spring MVC>>#
Spring WebFlux lets you handle CORS (Cross-Origin Resource Sharing). This section
describes how to do so.
[[webflux-cors-intro]]
== Introduction
[.small]#<<web.adoc#mvc-cors-intro,Same in Spring MVC>>#
[.small]#<<web.adoc#mvc-cors-intro,Same as in Spring MVC>>#
For security reasons browsers prohibit AJAX calls to resources outside the current origin.
For example you could have your bank account in one tab and evil.com in another. Scripts
For security reasons, browsers prohibit AJAX calls to resources outside the current origin.
For example, you could have your bank account in one tab and evil.com in another. Scripts
from evil.com should not be able to make AJAX requests to your bank API with your
credentials, e.g. withdrawing money from your account!
credentials -- for example, withdrawing money from your account!
Cross-Origin Resource Sharing (CORS) is a http://www.w3.org/TR/cors/[W3C specification]
implemented by http://caniuse.com/#feat=cors[most browsers] that allows you to specify
what kind of cross domain requests are authorized rather than using less secure and less
implemented by http://caniuse.com/#feat=cors[most browsers] that lets you specify
what kind of cross-domain requests are authorized, rather than using less secure and less
powerful workarounds based on IFRAME or JSONP.
[[webflux-cors-processing]]
== Processing
[.small]#<<web.adoc#mvc-cors-processing,Same in Spring MVC>>#
[.small]#<<web.adoc#mvc-cors-processing,Same as in Spring MVC>>#
The CORS specification distinguishes between preflight, simple, and actual requests.
To learn how CORS works, you can read
https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS[this article], among
many others, or refer to the specification for more details.
many others, or see the specification for more details.
Spring WebFlux ``HandlerMapping``'s provide built-in support for CORS. After successfully
mapping a request to a handler, ``HandlerMapping``'s check the CORS configuration for the
given request and handler and take further actions. Preflight requests are handled
directly while simple and actual CORS requests are intercepted, validated, and have
Spring WebFlux `HandlerMapping` implementations provide built-in support for CORS. After successfully
mapping a request to a handler, a `HandlerMapping` checks the CORS configuration for the
given request and handler and takes further actions. Preflight requests are handled
directly, while simple and actual CORS requests are intercepted, validated, and have the
required CORS response headers set.
In order to enable cross-origin requests (i.e. the `Origin` header is present and
differs from the host of the request) you need to have some explicitly declared CORS
In order to enable cross-origin requests (that is, the `Origin` header is present and
differs from the host of the request), you need to have some explicitly declared CORS
configuration. If no matching CORS configuration is found, preflight requests are
rejected. No CORS headers are added to the responses of simple and actual CORS requests
and consequently browsers reject them.
and, consequently, browsers reject them.
Each `HandlerMapping` can be
{api-spring-framework}/web/reactive/handler/AbstractHandlerMapping.html#setCorsConfigurations-java.util.Map-[configured]
individually with URL pattern based `CorsConfiguration` mappings. In most cases applications
will use the WebFlux Java config to declare such mappings, which results in a single,
global map passed to all ``HadlerMappping``'s.
individually with URL pattern-based `CorsConfiguration` mappings. In most cases, applications
use the WebFlux Java configuration to declare such mappings, which results in a single,
global map passed to all `HadlerMappping` implementations.
Global CORS configuration at the `HandlerMapping` level can be combined with more
fine-grained, handler-level CORS configuration. For example annotated controllers can use
class or method-level `@CrossOrigin` annotations (other handlers can implement
You can combine global CORS configuration at the `HandlerMapping` level with more
fine-grained, handler-level CORS configuration. For example, annotated controllers can use
class- or method-level `@CrossOrigin` annotations (other handlers can implement
`CorsConfigurationSource`).
The rules for combining global and local configuration are generally additive -- e.g.
The rules for combining global and local configuration are generally additive -- for example,
all global and all local origins. For those attributes where only a single value can be
accepted such as `allowCredentials` and `maxAge`, the local overrides the global value. See
accepted, such as `allowCredentials` and `maxAge`, the local overrides the global value. See
{api-spring-framework}/web/cors/CorsConfiguration.html#combine-org.springframework.web.cors.CorsConfiguration-[`CorsConfiguration#combine(CorsConfiguration)`]
for more details.
[TIP]
====
To learn more from the source or make advanced customizations, check:
To learn more from the source or to make advanced customizations, see:
* `CorsConfiguration`
* `CorsProcessor`, `DefaultCorsProcessor`
* `CorsProcessor` and `DefaultCorsProcessor`
* `AbstractHandlerMapping`
====
[[webflux-cors-controller]]
== @CrossOrigin
[.small]#<<web.adoc#mvc-cors-controller,Same in Spring MVC>>#
== Using `@CrossOrigin`
[.small]#<<web.adoc#mvc-cors-controller,Same as in Spring MVC>>#
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,25 @@ 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
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:
`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 be used only where appropriate.
`maxAge` is set to 30 minutes.
`@CrossOrigin` is supported at the class level, too, and inherited by all methods.
The following example specifies a certain domain and sets `maxAge` to an hour:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -130,18 +138,21 @@ public class AccountController {
}
}
----
====
`CrossOrigin` can be used at both class and method-level:
You can use `@CrossOrigin` at both the class and the method level,
as the following example shows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@CrossOrigin(maxAge = 3600)
@CrossOrigin(maxAge = 3600) <1>
@RestController
@RequestMapping("/account")
public class AccountController {
@CrossOrigin("http://domain2.com")
@CrossOrigin("http://domain2.com") <2>
@GetMapping("/{id}")
public Mono<Account> retrieve(@PathVariable Long id) {
// ...
@ -153,31 +164,37 @@ public class AccountController {
}
}
----
<1> Using `@CrossOrigin` at the class level.
<2> Using `@CrossOrigin` at the method level.
====
[[webflux-cors-global]]
== Global Config
[.small]#<<web.adoc#mvc-cors-global,Same in Spring MVC>>#
== Global Configuration
[.small]#<<web.adoc#mvc-cors-global,Same as in Spring MVC>>#
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
WebFlux Java config 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
WebFlux Java configuration to do that.
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
should only be used where appropriate.
* `maxAge` is set to 30 minutes.
To enable CORS in the WebFlux Java config, use the `CorsRegistry` callback:
`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 be used only where appropriate.
`maxAge` is set to 30 minutes.
To enable CORS in the WebFlux Java configuration, you can use the `CorsRegistry` callback,
as the following example shows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -199,19 +216,22 @@ public class WebConfig implements WebFluxConfigurer {
}
}
----
====
[[webflux-cors-webfilter]]
== CORS WebFilter
[.small]#<<web.adoc#mvc-cors-filter,Same in Spring MVC>>#
== CORS `WebFilter`
[.small]#<<web.adoc#mvc-cors-filter,Same as in Spring MVC>>#
You can apply CORS support through the built-in
{api-spring-framework}/web/cors/reactive/CorsWebFilter.html[`CorsWebFilter`], which is a
good fit with <<webflux-fn,functional endpoints>>.
To configure the filter, you can declare a `CorsWebFilter` bean and pass a
`CorsConfigurationSource` to its constructor:
`CorsConfigurationSource` to its constructor, as the following example shows:
====
[source,java,indent=0]
[subs="verbatim"]
----
@ -234,4 +254,4 @@ CorsWebFilter corsFilter() {
return new CorsWebFilter(source);
}
----
====

View File

@ -1,31 +1,31 @@
[[webflux-fn]]
= Functional Endpoints
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 {
}
}
----
====
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
* `RouterFunctions.toHttpHandler(RouterFunction)`
* `RouterFunctions.toHttpHandler(RouterFunction, HandlerStrategies)`
Most applications will run through the WebFlux Java config, see <<webflux-fn-running>>.
Most applications can run through the WebFlux Java configuration, see <<webflux-fn-running>>.
[[webflux-fn-handler-functions]]
== HandlerFunction
`ServerRequest` and `ServerResponse` are immutable interfaces that offer JDK-8 friendly
`ServerRequest` and `ServerResponse` are immutable interfaces that offer JDK 8-friendly
access to the HTTP request and response with
http://www.reactive-streams.org[Reactive Streams] back pressure against the request
and response body stream. The request body is represented with a Reactor `Flux` or `Mono`.
The response body is represented with any Reactive Streams `Publisher`, including `Flux`
and `Mono`. For more on that see
and `Mono`. For more on that, see
<<web-reactive.adoc#webflux-reactive-libraries,Reactive Libraries>>.
[[webflux-fn-request]]
=== ServerRequest
=== Using `ServerRequest`
`ServerRequest` provides access to the HTTP method, URI, headers, and query parameters
`ServerRequest` provides access to the HTTP method, URI, headers, and query parameters,
while access to the body is provided through the `body` methods.
To extract the request body to a `Mono<String>`:
The following example extracts the request body to a `Mono<String>`:
Mono<String> string = request.bodyToMono(String.class);
====
[source,java]
----
Mono<String> string = request.bodyToMono(String.class);
----
====
To extract the body to a `Flux<Person>`, where `Person` objects are decoded from some
The following example extracts the body to a `Flux<Person>`, where `Person` objects are decoded from some
serialized form, such as JSON or XML:
Flux<Person> people = request.bodyToFlux(Person.class);
====
[source,java]
----
Flux<Person> people = request.bodyToFlux(Person.class);
----
====
The above are shortcuts that use the more general `ServerRequest.body(BodyExtractor)`
which accepts the `BodyExtractor` functional, strategy interface. The utility class
`BodyExtractors` provides access to a number of instances. For example, the above can
The preceding examples are shortcuts that use the more general `ServerRequest.body(BodyExtractor)`,
which accepts the `BodyExtractor` functional strategy interface. The utility class
`BodyExtractors` provides access to a number of instances. For example, the preceding examples can
also be written as follows:
Mono<String> string = request.body(BodyExtractors.toMono(String.class));
Flux<Person> people = request.body(BodyExtractors.toFlux(Person.class));
====
[source,java]
----
Mono<String> string = request.body(BodyExtractors.toMono(String.class));
Flux<Person> people = request.body(BodyExtractors.toFlux(Person.class));
----
====
To access form data:
The following example shows how to access form data:
Mono<MultiValueMap<String, String> map = request.body(BodyExtractors.toFormData());
====
[source,java]
----
Mono<MultiValueMap<String, String> map = request.body(BodyExtractors.toFormData());
----
====
To access multipart data as a map:
The following example shows how to access multipart data as a map:
Mono<MultiValueMap<String, Part> map = request.body(BodyExtractors.toMultipartData());
====
[source,java]
----
Mono<MultiValueMap<String, Part> map = request.body(BodyExtractors.toMultipartData());
----
====
To access multiparts, one at a time, in streaming fashion:
The following example shows how to access multiparts, one at a time, in streaming fashion:
Flux<Part> parts = request.body(BodyExtractos.toParts());
====
[source,java]
----
Flux<Part> parts = request.body(BodyExtractos.toParts());
----
====
[[webflux-fn-response]]
=== ServerResponse
=== Using `ServerResponse`
`ServerResponse` provides access to the HTTP response and since it is immutable, you use
a build to create it. The builder can be used to set the response status, to add response
headers, or to provide a body. Below is an example with a 200 (OK) response with JSON
`ServerResponse` provides access to the HTTP response and, since it is immutable, you can use
a `build` method to create it. You can use the builder to set the response status, to add response
headers, or to provide a body. The following example creates a 200 (OK) response with JSON
content:
Mono<Person> person = ...
ServerResponse.ok().contentType(MediaType.APPLICATION_JSON).body(person, Person.class);
====
[source,java]
----
Mono<Person> person = ...
ServerResponse.ok().contentType(MediaType.APPLICATION_JSON).body(person, Person.class);
----
====
This is how to build a 201 (CREATED) response with `"Location"` header, and no body:
The following example shows how to build a 201 (CREATED) response with a `Location` header and no body:
URI location = ...
ServerResponse.created(location).build();
====
[source,java]
----
URI location = ...
ServerResponse.created(location).build();
----
====
[[webflux-fn-handler-classes]]
=== Handler Classes
We can write a handler function as a lambda. For example:
We can write a handler function as a lambda, as the following example shows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
HandlerFunction<ServerResponse> helloWorld =
request -> ServerResponse.ok().body(fromObject("Hello World"));
----
====
That is convenient but in an application we need multiple functions and useful to group
related handler functions together into a handler (like an `@Controller`). For example,
here is a class that exposes a reactive `Person` repository:
That is convenient, but, in an application, we need multiple functions, and it is useful to group
related handler functions together into a handler (like a `@Controller`). For example,
the following class exposes a reactive `Person` repository:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -192,35 +234,36 @@ public class PersonHandler {
<1> `listPeople` is a handler function that returns all `Person` objects found in the repository as
JSON.
<2> `createPerson` is a handler function that stores a new `Person` contained in the request body.
Note that `PersonRepository.savePerson(Person)` returns `Mono<Void>`: an empty Mono that emits
Note that `PersonRepository.savePerson(Person)` returns `Mono<Void>`: an empty `Mono` that emits
a completion signal when the person has been read from the request and stored. So we use the
`build(Publisher<Void>)` method to send a response when that completion signal is received, i.e.
when the `Person` has been saved.
<3> `getPerson` is a handler function that returns a single person, identified via the path
variable `id`. We retrieve that `Person` via the repository, and create a JSON response if it is
`build(Publisher<Void>)` method to send a response when that completion signal is received (that is,
when the `Person` has been saved).
<3> `getPerson` is a handler function that returns a single person, identified by the `id` path
variable. We retrieve that `Person` from the repository and create a JSON response, if it is
found. If it is not found, we use `switchIfEmpty(Mono<T>)` to return a 404 Not Found response.
====
[[webflux-fn-router-functions]]
== RouterFunction
== Using `RouterFunction`
`RouterFunction` is used to route requests to a `HandlerFunction`. Typically, you do not
write router functions yourself, but rather use
`RouterFunctions.route(RequestPredicate, HandlerFunction)`. If the predicate applies, the
request is routed to the given `HandlerFunction`, or otherwise no routing is performed,
request is routed to the given `HandlerFunction`. Otherwise, no routing is performed,
and that would translate to a 404 (Not Found) response.
[[webflux-fn-predicates]]
=== Predicates
=== Using Predicates
You can write your own `RequestPredicate`, but the `RequestPredicates` utility class
offers commonly implementations, based on the request path, HTTP method, content-type,
and so on. For example:
offers commonly used implementations, based on the request path, HTTP method, content-type,
and so on. The following example creates a request predicate based on a path:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -228,18 +271,19 @@ RouterFunction<ServerResponse> route =
RouterFunctions.route(RequestPredicates.path("/hello-world"),
request -> Response.ok().body(fromObject("Hello World")));
----
====
You can compose multiple request predicates together via:
You can compose multiple request predicates together by using:
* `RequestPredicate.and(RequestPredicate)` -- both must match.
* `RequestPredicate.or(RequestPredicate)` -- either may match.
* `RequestPredicate.or(RequestPredicate)` -- either can match.
Many of the predicates from `RequestPredicates` are composed. For example
Many of the predicates from `RequestPredicates` are composed. For example,
`RequestPredicates.GET(String)` is composed from `RequestPredicates.method(HttpMethod)`
and `RequestPredicates.path(String)`.
You can compose multiple router functions into one, such that they're evaluated in order,
and if the first route doesn't match, the second is evaluated. You can declare more
You can compose multiple router functions into one, such that they are evaluated in order,
and, if the first route does not match, the second is evaluated. You can declare more
specific routes before more general ones.
@ -247,16 +291,17 @@ specific routes before more general ones.
[[webflux-fn-routes]]
=== Routes
You can compose multiple router functions together via:
You can compose multiple router functions together by using:
* `RouterFunction.and(RouterFunction)`
* `RouterFunction.andRoute(RequestPredicate, HandlerFunction)` -- shortcut for
`RouterFunction.and()` with nested `RouterFunctions.route()`.
Using composed routes and predicates, we can then declare the following routes, referring
to methods in the `PersonHandler`, shown in <<webflux-fn-handler-class>>, through
to methods in the `PersonHandler` (shown in <<webflux-fn-handler-class>>) through
https://docs.oracle.com/javase/tutorial/java/javaOO/methodreferences.html[method-references]:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -271,45 +316,45 @@ RouterFunction<ServerResponse> personRoute =
.andRoute(GET("/person").and(accept(APPLICATION_JSON)), handler::listPeople)
.andRoute(POST("/person"), handler::createPerson);
----
====
[[webflux-fn-running]]
== Running a server
== Running a Server
How do you run a router function in an HTTP server? A simple option is to convert a router
function to an `HttpHandler` using one of the following:
function to an `HttpHandler` by using one of the following:
* `RouterFunctions.toHttpHandler(RouterFunction)`
* `RouterFunctions.toHttpHandler(RouterFunction, HandlerStrategies)`
The returned `HttpHandler` can then be used with a number of servers adapters by following
You can then use the returned `HttpHandler` with a number of server adapters by following
<<web-reactive.adoc#webflux-httphandler,HttpHandler>> for server-specific instructions.
A more advanced option is to run with a
<<web-reactive.adoc#webflux-dispatcher-handler,DispatcherHandler>>-based setup through the
<<web-reactive.adoc#webflux-config>> which uses Spring configuration to declare the
components quired to process requests. The WebFlux Java config declares the following
<<web-reactive.adoc#webflux-dispatcher-handler,`DispatcherHandler`>>-based setup through the
<<web-reactive.adoc#webflux-config>>, which uses Spring configuration to declare the
components required to process requests. The WebFlux Java configuration declares the following
infrastructure components to support functional endpoints:
* `RouterFunctionMapping` -- detects one or more `RouterFunction<?>` beans in the Spring
configuration, combines them via `RouterFunction.andOther`, and routes requests to the
* `RouterFunctionMapping`: Detects one or more `RouterFunction<?>` beans in the Spring
configuration, combines them through `RouterFunction.andOther`, and routes requests to the
resulting composed `RouterFunction`.
* `HandlerFunctionAdapter` -- simple adapter that allows the `DispatcherHandler` to invoke
* `HandlerFunctionAdapter`: Simple adapter that lets `DispatcherHandler` invoke
a `HandlerFunction` that was mapped to a request.
* `ServerResponseResultHandler` -- handles the result from the invocation of a
* `ServerResponseResultHandler`: Handles the result from the invocation of a
`HandlerFunction` by invoking the `writeTo` method of the `ServerResponse`.
The above components allow functional endpoints to fit within the `DispatcherHandler` request
processing lifecycle, and also potentially run side by side with annotated controllers, if
any are declared. It is also how functional endpoints are enabled the Spring Boot WebFlux
The preceding components let functional endpoints fit within the `DispatcherHandler` request
processing lifecycle and also (potentially) run side by side with annotated controllers, if
any are declared. It is also how functional endpoints are enabled by the Spring Boot WebFlux
starter.
Below is example WebFlux Java config (see
<<web-reactive.adoc#webflux-dispatcher-handler,DispatcherHandler>> for how to run):
The following example shows a WebFlux Java configuration (see
<<web-reactive.adoc#webflux-dispatcher-handler,DispatcherHandler>> for how to run it):
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -345,23 +390,24 @@ public class WebConfig implements WebFluxConfigurer {
}
}
----
====
[[webflux-fn-handler-filter-function]]
== HandlerFilterFunction
== Using `HandlerFilterFunction`
Routes mapped by a router function can be filtered by calling
You can filter routes mapped by a router function by calling
`RouterFunction.filter(HandlerFilterFunction)`, where `HandlerFilterFunction` is essentially a
function that takes a `ServerRequest` and `HandlerFunction`, and returns a `ServerResponse`.
The handler function parameter represents the next element in the chain: this is typically the
`HandlerFunction` that is routed to, but can also be another `FilterFunction` if multiple filters
function that takes a `ServerRequest` and `HandlerFunction` and returns a `ServerResponse`.
The handler function parameter represents the next element in the chain. This is typically the
`HandlerFunction` that is routed to, but it can also be another `FilterFunction` if multiple filters
are applied.
With annotations, similar functionality can be achieved using `@ControllerAdvice` and/or a `ServletFilter`.
Let's add a simple security filter to our route, assuming that we have a `SecurityManager` that
can determine whether a particular path is allowed:
With annotations, you can achieve similar functionality by using `@ControllerAdvice`, a `ServletFilter`, or both.
Now we can add a simple security filter to our route, assuming that we have a `SecurityManager` that
can determine whether a particular path is allowed. The following example shows how to do so:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -380,11 +426,9 @@ RouterFunction<ServerResponse> filteredRoute =
}
});
----
You can see in this example that invoking the `next.handle(ServerRequest)` is optional: we only
allow the handler function to be executed when access is allowed.
[NOTE]
====
CORS support for functional endpoints is provided via a dedicated <<webflux-cors-webfilter,`CorsWebFilter`>>.
====
The preceding example demonstrates that invoking the `next.handle(ServerRequest)` is optional. We
allow only the handler function to be executed when access is allowed.
NOTE: CORS support for functional endpoints is provided through a dedicated <<webflux-cors-webfilter,`CorsWebFilter`>>.

View File

@ -1,52 +1,51 @@
[[webflux-view]]
= View Technologies
[.small]#<<web.adoc#mvc-view,Same in Spring MVC>>#
[.small]#<<web.adoc#mvc-view,Same as in Spring MVC>>#
The use of view technologies in Spring WebFlux is pluggable, whether you decide to
use Thymeleaf, FreeMarker, or other, is primarily a matter of a configuration change.
This chapter covers view technologies integrated with Spring WebFlux. We assume you are
The use of view technologies in Spring WebFlux is pluggable. Whether you decide to
use Thymeleaf, FreeMarker, or some other view technology is primarily a matter of a configuration change.
This chapter covers the view technologies integrated with Spring WebFlux. We assume you are
already familiar with <<webflux-viewresolution>>.
[[webflux-view-thymeleaf]]
== Thymeleaf
[.small]#<<web.adoc#mvc-view-thymeleaf,Same in Spring MVC>>#
[.small]#<<web.adoc#mvc-view-thymeleaf,Same as in Spring MVC>>#
Thymeleaf is modern server-side Java template engine that emphasizes natural HTML
Thymeleaf is a modern server-side Java template engine that emphasizes natural HTML
templates that can be previewed in a browser by double-clicking, which is very
helpful for independent work on UI templates, e.g. by designer, without the need for a
running server. Thymeleaf offers an extensive set of features and it is actively developed
and maintained. For a more complete introduction see the
helpful for independent work on UI templates (for example, by a designer) without the need for a
running server. Thymeleaf offers an extensive set of features, and it is actively developed
and maintained. For a more complete introduction, see the
http://www.thymeleaf.org/[Thymeleaf] project home page.
The Thymeleaf integration with Spring WebFlux is managed by the Thymeleaf project. The
configuration involves a few bean declarations such as
configuration involves a few bean declarations, such as
`SpringResourceTemplateResolver`, `SpringWebFluxTemplateEngine`, and
`ThymeleafReactiveViewResolver`. For more details see
`ThymeleafReactiveViewResolver`. For more details, see
http://www.thymeleaf.org/documentation.html[Thymeleaf+Spring] and the WebFlux integration
http://forum.thymeleaf.org/Thymeleaf-3-0-8-JUST-PUBLISHED-td4030687.html[announcement].
[[webflux-view-freemarker]]
== FreeMarker
[.small]#<<web.adoc#mvc-view-freemarker,Same in Spring MVC>>#
[.small]#<<web.adoc#mvc-view-freemarker,Same as in Spring MVC>>#
http://www.freemarker.org[Apache FreeMarker] is a template engine for generating any
kind of text output from HTML to email, and others. The Spring Framework has a built-in
kind of text output from HTML to email and others. The Spring Framework has a built-in
integration for using Spring WebFlux with FreeMarker templates.
[[webflux-view-freemarker-contextconfig]]
=== View config
[.small]#<<web.adoc#mvc-view-freemarker-contextconfig,Same in Spring MVC>>#
=== View Configuration
[.small]#<<web.adoc#mvc-view-freemarker-contextconfig,Same as in Spring MVC>>#
To configure FreeMarker as a view technology:
The following example shows how to configure FreeMarker as a view technology:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -69,24 +68,26 @@ To configure FreeMarker as a view technology:
}
}
----
====
Your templates need to be stored in the directory specified by the `FreeMarkerConfigurer`
shown above. Given the above configuration if your controller returns the view name
"welcome" then the resolver will look for the
Your templates need to be stored in the directory specified by the `FreeMarkerConfigurer`,
shown in the preceding example. Given the preceding configuration, if your controller returns the view name,
`welcome`, the resolver looks for the
`classpath:/templates/freemarker/welcome.ftl` template.
[[webflux-views-freemarker]]
=== FreeMarker config
[.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
}
}
----
====
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:
https://www.jcp.org/en/jsr/detail?id=223[JSR-223] Java scripting engine.
The following table shows the templating libraries that we have tested on different script engines:
[horizontal]
http://handlebarsjs.com/[Handlebars] :: http://openjdk.java.net/projects/nashorn/[Nashorn]
https://mustache.github.io/[Mustache] :: http://openjdk.java.net/projects/nashorn/[Nashorn]
http://facebook.github.io/react/[React] :: http://openjdk.java.net/projects/nashorn/[Nashorn]
http://www.embeddedjs.com/[EJS] :: http://openjdk.java.net/projects/nashorn/[Nashorn]
http://www.stuartellis.eu/articles/erb/[ERB] :: http://jruby.org[JRuby]
https://docs.python.org/2/library/string.html#template-strings[String templates] :: http://www.jython.org/[Jython]
https://github.com/sdeleuze/kotlin-script-templating[Kotlin Script templating] :: http://kotlinlang.org/[Kotlin]
[%header]
|===
|Scripting Library |Scripting Engine
|http://handlebarsjs.com/[Handlebars] |http://openjdk.java.net/projects/nashorn/[Nashorn]
|https://mustache.github.io/[Mustache] |http://openjdk.java.net/projects/nashorn/[Nashorn]
|http://facebook.github.io/react/[React] |http://openjdk.java.net/projects/nashorn/[Nashorn]
|http://www.embeddedjs.com/[EJS] |http://openjdk.java.net/projects/nashorn/[Nashorn]
|http://www.stuartellis.eu/articles/erb/[ERB] |http://jruby.org[JRuby]
|https://docs.python.org/2/library/string.html#template-strings[String templates] |http://www.jython.org/[Jython]
|https://github.com/sdeleuze/kotlin-script-templating[Kotlin Script templating] |http://kotlinlang.org/[Kotlin]
|===
[TIP]
====
The basic rule for integrating any other script engine is that it must implement the
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].
[[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:
}
}
----
====
The render function is called with the following parameters:
The `render` function is called with the following parameters:
* `String template`: the template content
* `Map model`: the view model
* `RenderingContext renderingContext`: the
{api-spring-framework}/web/servlet/view/script/RenderingContext.html[RenderingContext]
that gives access to the application context, the locale, the template loader and the
url (since 5.0)
* `String template`: The template content
* `Map model`: The view model
* `RenderingContext renderingContext`: The
{api-spring-framework}/web/servlet/view/script/RenderingContext.html[`RenderingContext`]
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.
}
}
----
[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` defines only the `window` object needed by Handlebars to run properly,
as the following snippet shows:
====
`polyfill.js` only defines the `window` object needed by Handlebars to run properly:
[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).
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
https://github.com/spring-projects/spring-framework/tree/master/spring-webflux/src/test/resources/org/springframework/web/reactive/result/view/script[resources],
for more configuration examples.
[[webflux-view-httpmessagewriter]]
== JSON, XML
[.small]#<<web.adoc#mvc-view-jackson,Same in Spring MVC>>#
== JSON and XML
[.small]#<<web.adoc#mvc-view-jackson,Same as in Spring MVC>>#
For <<webflux-multiple-representations>> purposes it is useful to be able to alternate
between rendering a model with an HTML template or as other formats such as JSON or XML,
depending on the content type requested by the client. To support this Spring WebFlux
provides the `HttpMessageWriterView` that can be used to plug in any of the available
<<webflux-codecs>> from `spring-web` such as `Jackson2JsonEncoder`,
For <<webflux-multiple-representations>> purposes, it is useful to be able to alternate
between rendering a model with an HTML template or as other formats (such as JSON or XML),
depending on the content type requested by the client. To support doing so, Spring WebFlux
provides the `HttpMessageWriterView`, which you can use to plug in any of the available
<<webflux-codecs>> from `spring-web`, such as `Jackson2JsonEncoder`,
`Jackson2SmileEncoder`, or `Jaxb2XmlEncoder`.
Unlike other view technologies, `HttpMessageWriterView` does not require a `ViewResolver`,
but instead is <<webflux-config-view-resolvers,configured>> as a default view. You can
configure one more such default views, wrapping different ``HttpMessageWriter``'s or
``Encoder``'s. The one that matches the requested content type is used at runtime.
In most cases a model will contain multiple attributes. In order to determine which one
to serialize, `HttpMessageWriterView` can be configured with the name of the model
attribute to use render, of if the model contains only one attribute, it will be used.
Unlike other view technologies, `HttpMessageWriterView` does not require a `ViewResolver`
but is instead <<webflux-config-view-resolvers,configured>> as a default view. You can
configure one or more such default views, wrapping different `HttpMessageWriter` instances or
`Encoder` instances. The one that matches the requested content type is used at runtime.
In most cases, a model contains multiple attributes. To determine which one
to serialize, you can configure `HttpMessageWriterView` with the name of the model
attribute to use for rendering. If the model contains only one attribute, that one is used.

View File

@ -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
* `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.
* `filter` -- client filter for every request.
* `exchangeStrategies` -- HTTP message reader/writer customizations.
* `clientConnector` -- HTTP client library settings.
* `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.
* `filter`: Client filter for every request.
* `exchangeStrategies`: HTTP message reader/writer customizations.
* `clientConnector`: HTTP client library settings.
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>>:
.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:
// 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:
WebClient webClient = WebClient.builder().clientConnector(connector).build();
----
====
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
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:
}
----
<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:
WebClient webClient = WebClient.builder().clientConnector(connector).build();
----
====
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`:
----
<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:
.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:
.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:
.onStatus(HttpStatus::is5xxServerError, response -> ...)
.bodyToMono(Person.class);
----
====
[[webflux-client-exchange]]
== Exchange
== Using the `exchange` Method
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`:
.exchange()
.flatMap(response -> response.bodyToMono(Person.class));
----
====
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`:
.exchange()
.flatMap(response -> response.toEntity(Person.class));
----
====
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:
.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:
.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:
.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
.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`:
.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, ?>`:
[source,java,intent=0]
[subs="verbatim,quotes"]
@ -379,15 +412,16 @@ multipart request:
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:
.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:
.retrieve()
.bodyToMono(Void.class);
----
====
@ -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:
====
[source,java,intent=0]
[subs="verbatim,quotes"]
----
@ -443,10 +480,12 @@ WebClient client = WebClient.builder()
})
.build();
----
====
This can be used for cross-cutting concerns such as authentication. The example below uses
This can be used for cross-cutting concerns, such as authentication. The following example uses
a filter for basic authentication through a static factory method:
====
[source,java,intent=0]
[subs="verbatim,quotes"]
----
@ -457,11 +496,13 @@ WebClient client = WebClient.builder()
.filter(basicAuthentication("user", "password"))
.build();
----
====
Filters apply globally to every request. To change how a filter's behavior for a specific
Filters apply globally to every request. To change a filter's behavior for a specific
request, you can add request attributes to the `ClientRequest` that can then be accessed
by all filters in the chain:
by all filters in the chain, as the following example shows:
====
[source,java,intent=0]
[subs="verbatim,quotes"]
----
@ -479,11 +520,13 @@ client.get().uri("http://example.org/")
}
----
====
You can also replicate an existing `WebClient`, and insert new filters or remove already
registered filters. In the example below, a basic authentication filter is inserted at
You can also replicate an existing `WebClient`, insert new filters, or remove already
registered filters. The following example, inserts a basic authentication filter at
index 0:
====
[source,java,intent=0]
[subs="verbatim,quotes"]
----
@ -496,17 +539,17 @@ WebClient client = webClient.mutate()
})
.build();
----
====
[[webflux-client-testing]]
== Testing
To test code that uses the `WebClient`, you can use a mock web server such as the
https://github.com/square/okhttp#mockwebserver[OkHttp MockWebServer]. To see example
use, check
https://github.com/spring-projects/spring-framework/blob/master/spring-webflux/src/test/java/org/springframework/web/reactive/function/client/WebClientIntegrationTests.java[WebClientIntegrationTests]
in the Spring Framework tests, or the
https://github.com/square/okhttp/tree/master/samples/static-server[static-server]
To test code that uses the `WebClient`, you can use a mock web server, such as the
https://github.com/square/okhttp#mockwebserver[OkHttp MockWebServer]. To see an example
of its use, check
https://github.com/spring-projects/spring-framework/blob/master/spring-webflux/src/test/java/org/springframework/web/reactive/function/client/WebClientIntegrationTests.java[`WebClientIntegrationTests`]
in the Spring Framework tests or the
https://github.com/square/okhttp/tree/master/samples/static-server[`static-server`]
sample in the OkHttp repository.

View File

@ -1,30 +1,33 @@
[[webflux-websocket]]
= WebSockets
[.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
server side 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`:
}
}
----
====
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`:
}
}
----
====
[[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:
|===
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 {
}
}
----
<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 following implementation combines the inbound and outbound streams:
====
The below implementation combines the inbound with the outbound streams:
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -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 {
----
<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`.
[[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:
}
}
----
====
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
=== 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`
methods:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -282,7 +293,8 @@ client.execute(url, session ->
.doOnNext(System.out::println)
.then());
----
====
Some clients, e.g. Jetty, implement `Lifecycle` and need to be started in stopped
Some clients, such as Jetty, implement `Lifecycle` and need to be stopped and started
before you can use them. All clients have constructor options related to configuration
of the underlying WebSocket client.

File diff suppressed because it is too large Load Diff

View File

@ -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.

View File

@ -1,68 +1,69 @@
[[mvc-cors]]
= CORS
[.small]#<<web-reactive.adoc#webflux-cors,Same in Spring WebFlux>>#
[.small]#<<web-reactive.adoc#webflux-cors,Same as in Spring WebFlux>>#
Spring MVC lets you handle CORS (Cross-Origin Resource Sharing). This section
describes how to do so.
[[mvc-cors-intro]]
== Introduction
[.small]#<<web-reactive.adoc#webflux-cors-intro,Same in Spring WebFlux>>#
[.small]#<<web-reactive.adoc#webflux-cors-intro,Same as in Spring WebFlux>>#
For security reasons browsers prohibit AJAX calls to resources outside the current origin.
For example you could have your bank account in one tab and evil.com in another. Scripts
For security reasons, browsers prohibit AJAX calls to resources outside the current origin.
For example, you could have your bank account in one tab and evil.com in another. Scripts
from evil.com should not be able to make AJAX requests to your bank API with your
credentials, e.g. withdrawing money from your account!
credentials -- for example withdrawing money from your account!
Cross-Origin Resource Sharing (CORS) is a http://www.w3.org/TR/cors/[W3C specification]
implemented by http://caniuse.com/#feat=cors[most browsers] that allows you to specify
what kind of cross domain requests are authorized rather than using less secure and less
implemented by http://caniuse.com/#feat=cors[most browsers] that lets you specify
what kind of cross-domain requests are authorized, rather than using less secure and less
powerful workarounds based on IFRAME or JSONP.
[[mvc-cors-processing]]
== Processing
[.small]#<<web-reactive.adoc#webflux-cors-processing,Same in Spring WebFlux>>#
[.small]#<<web-reactive.adoc#webflux-cors-processing,Same as in Spring WebFlux>>#
The CORS specification distinguishes between preflight, simple, and actual requests.
To learn how CORS works, you can read
https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS[this article], among
many others, or refer to the specification for more details.
many others, or see the specification for more details.
Spring MVC ``HandlerMapping``'s provide built-in support for CORS. After successfully
mapping a request to a handler, ``HandlerMapping``'s check the CORS configuration for the
Spring MVC `HandlerMapping` implementations provide built-in support for CORS. After successfully
mapping a request to a handler, `HandlerMapping` implementations check the CORS configuration for the
given request and handler and take further actions. Preflight requests are handled
directly while simple and actual CORS requests are intercepted, validated, and have
directly, while simple and actual CORS requests are intercepted, validated, and have
required CORS response headers set.
In order to enable cross-origin requests (i.e. the `Origin` header is present and
differs from the host of the request) you need to have some explicitly declared CORS
In order to enable cross-origin requests (that is, the `Origin` header is present and
differs from the host of the request), you need to have some explicitly declared CORS
configuration. If no matching CORS configuration is found, preflight requests are
rejected. No CORS headers are added to the responses of simple and actual CORS requests
and consequently browsers reject them.
and, consequently, browsers reject them.
Each `HandlerMapping` can be
{api-spring-framework}/web/servlet/handler/AbstractHandlerMapping.html#setCorsConfigurations-java.util.Map-[configured]
individually with URL pattern based `CorsConfiguration` mappings. In most cases applications
will use the MVC Java config or the XML namespace to declare such mappings, which results
in a single, global map passed to all ``HadlerMappping``'s.
individually with URL pattern-based `CorsConfiguration` mappings. In most cases, applications
use the MVC Java configuration or the XML namespace to declare such mappings, which results
in a single global map being passed to all `HandlerMappping` instances.
Global CORS configuration at the `HandlerMapping` level can be combined with more
fine-grained, handler-level CORS configuration. For example annotated controllers can use
class or method-level `@CrossOrigin` annotations (other handlers can implement
You can combine global CORS configuration at the `HandlerMapping` level with more
fine-grained, handler-level CORS configuration. For example, annotated controllers can use
class- or method-level `@CrossOrigin` annotations (other handlers can implement
`CorsConfigurationSource`).
The rules for combining global and local configuration are generally additive -- e.g.
The rules for combining global and local configuration are generally additive -- for example,
all global and all local origins. For those attributes where only a single value can be
accepted such as `allowCredentials` and `maxAge`, the local overrides the global value. See
accepted (such as `allowCredentials` and `maxAge`), the local overrides the global value. See
{api-spring-framework}/web/cors/CorsConfiguration.html#combine-org.springframework.web.cors.CorsConfiguration-[`CorsConfiguration#combine(CorsConfiguration)`]
for more details.
[TIP]
====
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:
[[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 {
}
}
----
====
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 {
}
}
----
====
`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 {
}
}
----
====
[[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 {
}
}
----
====
[[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:
</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>>#
You can apply CORS support through the built-in
{api-spring-framework}/web/filter/CorsFilter.html[`CorsFilter`].
[NOTE]
====
If you're trying to use the `CorsFilter` with Spring Security, keep in mind that Spring
NOTE: If you try to use the `CorsFilter` with Spring Security, keep in mind that Spring
Security has
https://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/#cors[built-in support]
for CORS.
To configure the filter, pass a
`CorsConfigurationSource` to its constructor, as the following example shows:
====
To configure the filter pass a
`CorsConfigurationSource` to its constructor:
[source,java,indent=0]
[subs="verbatim"]
----
@ -271,4 +287,4 @@ source.registerCorsConfiguration("/**", config);
CorsFilter filter = new CorsFilter(source);
----
====

View File

@ -4,35 +4,25 @@
This section summarizes the options available in `spring-test` for Spring MVC applications.
**Servlet API Mocks**
Mock implementations of Servlet API contracts for unit testing controllers, filters, and
* Servlet API Mocks: Mock implementations of Servlet API contracts for unit testing controllers, filters, and
other web components. See <<testing.adoc#mock-objects-servlet,Servlet API>> mock objects
for more details.
**TestContext Framework**
Support for loading Spring configuration in JUnit and TestNG tests including efficient
* TestContext Framework: Support for loading Spring configuration in JUnit and TestNG tests, including efficient
caching of the loaded configuration across test methods and support for loading a
`WebApplicationContext` with a `MockServletContext`.
See <<testing.adoc#testcontext-framework,TestContext Framework>> for more details.
**Spring MVC Test**
A framework, also known as `MockMvc`, for testing annotated controllers through the
`DispatcherServlet`, i.e. supporting annotations and complete with Spring MVC
infrastructure, but without an HTTP server. See
* Spring MVC Test: A framework, also known as `MockMvc`, for testing annotated controllers through the
`DispatcherServlet` (that is, supporting annotations), complete with the Spring MVC
infrastructure but without an HTTP server. See
<<testing.adoc#spring-mvc-test-framework,Spring MVC Test>> for more details.
**Client-side REST**
`spring-test` provides a `MockRestServiceServer` that can be used as a mock server for
* Client-side REST: `spring-test` provides a `MockRestServiceServer` that you can use as a mock server for
testing client-side code that internally uses the `RestTemplate`.
See <<testing.adoc#spring-mvc-test-client,Client REST Tests>> for more details.
**WebTestClient**
`WebTestClient` was built for testing WebFlux applications but it can also be used for
* `WebTestClient`: Built for testing WebFlux applications, but it can also be used for
end-to-end integration testing, to any server, over an HTTP connection. It is a
non-blocking, reactive client and well suited for testing asynchronous and streaming
non-blocking, reactive client and is well suited for testing asynchronous and streaming
scenarios.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,28 +1,35 @@
[[websocket-intro]]
= Introduction
= Introduction to WebSocket
The WebSocket protocol http://tools.ietf.org/html/rfc6455[RFC 6455] provides a standardized
The WebSocket protocol, http://tools.ietf.org/html/rfc6455[RFC 6455], provides a standardized
way to establish a full-duplex, two-way communication channel between client and server
over a single TCP connection. It is a different TCP protocol from HTTP but is designed to
work over HTTP, using ports 80 and 443 and allowing re-use of existing firewall rules.
A WebSocket interaction begins with an HTTP request that uses the HTTP `"Upgrade"` header
to upgrade, or in this case to switch, to the WebSocket protocol:
A WebSocket interaction begins with an HTTP request that uses the HTTP `Upgrade` header
to upgrade or, in this case, to switch to the WebSocket protocol. The following example
shows such an interaction:
====
[subs="quotes"]
----
GET /spring-websocket-portfolio/portfolio HTTP/1.1
Host: localhost:8080
**Upgrade: websocket**
**Connection: Upgrade**
Upgrade: websocket <1>
Connection: Upgrade <2>
Sec-WebSocket-Key: Uc9l9TMkWGbHFD2qnFHltg==
Sec-WebSocket-Protocol: v10.stomp, v11.stomp
Sec-WebSocket-Version: 13
Origin: http://localhost:8080
----
<1> The `Upgrade` header.
<2> Using the `Upgrade` connection.
====
Instead of the usual 200 status code, a server with WebSocket support returns:
Instead of the usual 200 status code, a server with WebSocket support returns output
similar to the following:
====
[subs="quotes"]
----
**HTTP/1.1 101 Switching Protocols**
@ -31,65 +38,65 @@ Connection: Upgrade
Sec-WebSocket-Accept: 1qVdfYHU9hPOl4JYYNXF623Gzn0=
Sec-WebSocket-Protocol: v10.stomp
----
====
After a successful handshake the TCP socket underlying the HTTP upgrade request remains
open for both client and server to continue to send and receive messages.
After a successful handshake, the TCP socket underlying the HTTP upgrade request remains
open for both the client and the server to continue to send and receive messages.
A complete introduction of how WebSockets work is beyond the scope of this document.
Please read RFC 6455, the WebSocket chapter of HTML5, or one of many introductions and
See RFC 6455, the WebSocket chapter of HTML5, or any of the many introductions and
tutorials on the Web.
Note that if a WebSocket server is running behind a web server (e.g. nginx) you will
Note that, if a WebSocket server is running behind a web server (e.g. nginx), you
likely need to configure it to pass WebSocket upgrade requests on to the WebSocket
server. Likewise if the application runs in a cloud environment, check the
server. Likewise, if the application runs in a cloud environment, check the
instructions of the cloud provider related to WebSocket support.
[[websocket-intro-architecture]]
== HTTP vs WebSocket
== HTTP Versus WebSocket
Even though WebSocket is designed to be HTTP compatible and starts with an HTTP request,
Even though WebSocket is designed to be HTTP-compatible and starts with an HTTP request,
it is important to understand that the two protocols lead to very different
architectures and application programming models.
In HTTP and REST, an application is modeled as many URLs. To interact with the application
In HTTP and REST, an application is modeled as many URLs. To interact with the application,
clients access those URLs, request-response style. Servers route requests to the
appropriate handler based on the HTTP URL, method, and headers.
By contrast in WebSockets there is usually just one URL for the initial connect and
subsequently all application messages flow on that same TCP connection. This points to
By contrast, in WebSockets, there is usually only one URL for the initial connect.
Subsequently, all application messages flow on that same TCP connection. This points to
an entirely different asynchronous, event-driven, messaging architecture.
WebSocket is also a low-level transport protocol which unlike HTTP does not prescribe
any semantics to the content of messages. That means there is no way to route or process
a message unless client and server agree on message semantics.
WebSocket is also a low-level transport protocol, which, unlike HTTP, does not prescribe
any semantics to the content of messages. That means that there is no way to route or process
a message unless the client and the server agree on message semantics.
WebSocket clients and servers can negotiate the use of a higher-level, messaging protocol
(e.g. STOMP), via the `"Sec-WebSocket-Protocol"` header on the HTTP handshake request,
or in the absence of that they need to come up with their own conventions.
(for example, STOMP), through the `Sec-WebSocket-Protocol` header on the HTTP handshake request.
In the absence of that, they need to come up with their own conventions.
[[websocket-intro-when-to-use]]
== When to use it?
== When to Use WebSockets
WebSockets can make a web page dynamic and interactive. However in many cases
a combination of Ajax and HTTP streaming and/or long polling could provide a simple and
WebSockets can make a web page be dynamic and interactive. However, in many cases,
a combination of Ajax and HTTP streaming or long polling can provide a simple and
effective solution.
For example news, mail, and social feeds need to update dynamically but it may be
perfectly okay to do so every few minutes. Collaboration, games, and financial apps on
the other hand need to be much closer to real time.
For example, news, mail, and social feeds need to update dynamically, but it may be
perfectly okay to do so every few minutes. Collaboration, games, and financial apps, on
the other hand, need to be much closer to real-time.
Latency alone is not a deciding factor. If the volume of messages is relatively low (e.g.
monitoring network failures) HTTP streaming or polling may provide an effective solution.
It is the combination of low latency, high frequency and high volume that make the best
case for the use WebSocket.
Latency alone is not a deciding factor. If the volume of messages is relatively low (for example,
monitoring network failures) HTTP streaming or polling can provide an effective solution.
It is the combination of low latency, high frequency, and high volume that make the best
case for the use of WebSocket.
Keep in mind also that over the Internet, restrictive proxies outside your control,
may preclude WebSocket interactions either because they are not configured to pass on the
`Upgrade` header or because they close long lived connections that appear idle? This
Keep in mind also that over the Internet, restrictive proxies that are outside of your control
may preclude WebSocket interactions, either because they are not configured to pass on the
`Upgrade` header or because they close long-lived connections that appear idle. This
means that the use of WebSocket for internal applications within the firewall is a more
straight-forward decision than it is for public facing applications.
straightforward decision than it is for public facing applications.

File diff suppressed because it is too large Load Diff