Add WebSocket chapter to WebFlux section

Issue: SPR-15700
This commit is contained in:
Rossen Stoyanchev 2017-11-13 18:06:10 -05:00
parent 0dd31b834e
commit 536e72c8df
4 changed files with 187 additions and 23 deletions

View File

@ -171,7 +171,9 @@ public abstract class AbstractWebSocketIntegrationTests {
@Bean
public WebSocketService webSocketService() {
return new HandshakeWebSocketService(getUpgradeStrategy());
TomcatRequestUpgradeStrategy strategy = new TomcatRequestUpgradeStrategy();
strategy.setMaxSessionIdleTimeout(0L);
return new HandshakeWebSocketService(strategy);
}
protected abstract RequestUpgradeStrategy getUpgradeStrategy();

View File

@ -18,6 +18,7 @@ include::web/webflux.adoc[leveloffset=+1]
include::web/webflux-webclient.adoc[leveloffset=+1]
include::web/webflux-websocket.adoc[leveloffset=+1]

View File

@ -0,0 +1,167 @@
[[webflux-websocket]]
= WebSockets
[.small]#<<web.adoc#websocket,Same in Servlet stack>>#
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>>#
The Spring Framework provides a WebSocket API that can be used to write client and
server side applications that handle WebSocket messages.
[[webflux-websocket-server-handler]]
=== WebSocketHandler
[.small]#<<web.adoc#websocket-server-handler,Same in Servlet stack>>#
Creating a WebSocket server is as simple as implementing `WebSocketHandler`:
[source,java,indent=0]
[subs="verbatim,quotes"]
----
import org.springframework.web.reactive.socket.WebSocketHandler;
import org.springframework.web.reactive.socket.WebSocketSession;
public class MyWebSocketHandler implements WebSocketHandler {
@Override
public Mono<Void> handle(WebSocketSession session) {
// ...
}
}
----
Spring WebFlux provides a `WebSocketHandlerAdapter` that can adapt WebSocket
requests and use the above handler to handle the resulting WebSocket session. After the
adapter is registered as a bean, you can map requests to your handler, for example using
`SimpleUrlHandlerMapping`. This is shown below:
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@Configuration
static class WebConfig {
@Bean
public HandlerMapping handlerMapping() {
Map<String, WebSocketHandler> map = new HashMap<>();
map.put("/path", new MyWebSocketHandler());
SimpleUrlHandlerMapping mapping = new SimpleUrlHandlerMapping();
mapping.setUrlMap(map);
mapping.setOrder(-1); // before annotated controllers
return mapping;
}
@Bean
public WebSocketHandlerAdapter handlerAdapter() {
return new WebSocketHandlerAdapter();
}
}
----
[[webflux-websocket-server-handshake]]
=== WebSocket Handshake
[.small]#<<web.adoc#websocket-server-handshake,Same in Servlet stack>>#
`WebSocketHandlerAdapter` does not perform WebSocket handshakes itself. Instead it
delegates to an instance of `WebSocketService`. The default `WebSocketService`
implementation is `HandshakeWebSocketService`.
The `HandshakeWebSocketService` performs basic checks on the WebSocket request and
delegates to a server-specific `RequestUpgradeStrategy`. At present upgrade strategies
exist for Reactor Netty, Tomcat, Jetty, and Undertow.
[[webflux-websocket-server-config]]
=== Server config
[.small]#<<web.adoc#websocket-server-runtime-configuration,Same in Servlet stack>>#
The `RequestUpgradeStrategy` for each server exposes the WebSocket-related configuration
options available for the underlying WebSocket engine. Below is an example of setting
WebSocket options when running on Tomcat:
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@Configuration
static class WebConfig {
@Bean
public WebSocketHandlerAdapter handlerAdapter() {
return new WebSocketHandlerAdapter(webSocketService());
}
@Bean
public WebSocketService webSocketService() {
TomcatRequestUpgradeStrategy strategy = new TomcatRequestUpgradeStrategy();
strategy.setMaxSessionIdleTimeout(0L);
return new HandshakeWebSocketService(strategy);
}
}
----
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>>#
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
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
`combine` method on `CorsConfiguration`.
[[webflux-websocket-client]]
== WebSocketClient
Spring WebFlux provides a `WebSocketClient` abstraction with implementations for
Reactor Netty, Tomcat, Jetty, Undertow, and standard Java (i.e. 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
API to suspend receiving messages for back pressure.
====
To start a WebSocket session, create an instance of the client and use its `execute`
methods:
[source,java,indent=0]
[subs="verbatim,quotes"]
----
WebSocketClient client = new ReactorNettyWebSocketClient();
URI url = new URI("ws://localhost:8080/path");
client.execute(url, session ->
session.receive()
.doOnNext(System.out::println)
.then());
----
Some clients, e.g. Jetty, implement `Lifecycle` and need to be started in stopped
before you can use them. All clients have constructor options related to configuration
of the underlying WebSocket client.

View File

@ -1,6 +1,7 @@
[[websocket]]
= WebSockets
:doc-spring-security: {doc-root}/spring-security/site/docs/current/reference
[.small]#<<web-reactive.adoc#webflux-websocket,Same in Spring WebFlux>>#
This part of the reference documentation covers support for Servlet stack, WebSocket
messaging that includes raw WebSocket interactions, WebSocket emulation via SockJS, and
@ -10,32 +11,19 @@ pub-sub messaging via STOMP as a sub-protocol over WebSocket.
include::websocket-intro.adoc[leveloffset=+1]
[[websocket-server]]
== WebSocket API
[.small]#<<web-reactive.adoc#webflux-websocket-server,Same in Spring WebFlux>>#
The Spring Framework provides a WebSocket API designed to adapt to various WebSocket engines.
Currently the list includes WebSocket runtimes such as Tomcat 7.0.47+, Jetty 9.1+,
GlassFish 4.1+, WebLogic 12.1.3+, and Undertow 1.0+ (and WildFly 8.0+). Additional support
may be added as more WebSocket runtimes become available.
[NOTE]
====
As explained in the <<websocket-intro-sub-protocol,introduction>>, direct use of a
WebSocket API is too low level for applications -- until assumptions are made about the
format of a message there is little a framework can do to interpret messages or route
them via annotations. This is why applications should consider using a sub-protocol
and Spring's <<websocket-stomp>> support.
When using a higher level protocol, the details of the WebSocket API become less
relevant, much like the details of TCP communication are not exposed to applications
when using HTTP. Nevertheless this section covers the details of using WebSocket
directly.
====
The Spring Framework provides a WebSocket API that can be used to write client and
server side applications that handle WebSocket messages.
[[websocket-server-handler]]
=== WebSocketHandler
[.small]#<<web-reactive.adoc#webflux-websocket-server-handler,Same in Spring WebFlux>>#
Creating a WebSocket server is as simple as implementing `WebSocketHandler` or more
likely extending either `TextWebSocketHandler` or `BinaryWebSocketHandler`:
@ -117,6 +105,7 @@ into other HTTP serving environments with the help of
[[websocket-server-handshake]]
=== WebSocket Handshake
[.small]#<<web-reactive.adoc#webflux-websocket-server-handshake,Same in Spring WebFlux>>#
The easiest way to customize the initial HTTP WebSocket handshake request is through
a `HandshakeInterceptor`, which exposes "before" and "after" the handshake methods.
@ -204,16 +193,19 @@ Neither of these mechanism makes it possible to use a single "front controller"
for all HTTP processing -- including WebSocket handshake and all other HTTP
requests -- such as Spring MVC's `DispatcherServlet`.
This is a significant limitation of JSR-356 that Spring's WebSocket support
addresses by providing a server-specific `RequestUpgradeStrategy` even when
running in a JSR-356 runtime.
This is a significant limitation of JSR-356 that Spring's WebSocket support addresses
server-specific ``RequestUpgradeStrategy``'s even when running in a JSR-356 runtime.
Such strategies currently exist for Tomcat, Jetty, GlassFish, WebLogic, WebSphere, and
Undertow (and WildFly).
[NOTE]
====
A request to overcome the above limitation in the Java WebSocket API has been
created and can be followed at
https://java.net/jira/browse/WEBSOCKET_SPEC-211[WEBSOCKET_SPEC-211].
Also note that Tomcat and Jetty already provide native API alternatives that
Tomcat, Jetty, and WebSphere provide their own API alternatives that
makes it easy to overcome the limitation. We are hopeful that more servers
will follow their example regardless of when it is addressed in the
Java WebSocket API.
@ -266,6 +258,7 @@ Java initialization API, if required:
[[websocket-server-runtime-configuration]]
=== Server config
[.small]#<<web-reactive.adoc#webflux-websocket-server-config,Same in Spring WebFlux>>#
Each underlying WebSocket engine exposes configuration properties that control
runtime characteristics such as the size of message buffer sizes, idle timeout,
@ -394,6 +387,7 @@ or WebSocket XML namespace:
[[websocket-server-allowed-origins]]
=== Allowed origins
[.small]#<<web-reactive.adoc#webflux-websocket-server-cors,Same in Spring WebFlux>>#
As of Spring Framework 4.1.5, the default behavior for WebSocket and SockJS is to accept
only _same origin_ requests. It is also possible to allow _all_ or a specified list of origins.