165 lines
		
	
	
		
			4.9 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
			
		
		
	
	
			165 lines
		
	
	
		
			4.9 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
| [[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.
 |