官方地址:SpringBoot WebSockets
原作者地址:http://www.caijp.xyz/archives/springboot-websocket
webSocket 介绍
WebSocket协议RFC 6455提供了一种标准化的方式来建立一个全双工,客户端和服务器之间的双向通信信道在一个TCP连接。
WebSocket 交互始于一个HTTP请求,HTTP请求的header中携带Upgrade参数,对应的值是WebSocket,header中的Connection参数对应的值是Upgrade。
GET /spring-websocket-portfolio/portfolio HTTP/1.1
Host: localhost:8080
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: Uc9l9TMkWGbHFD2qnFHltg==
Sec-WebSocket-Protocol: v10.stomp, v11.stomp
Sec-WebSocket-Version: 13
Origin: http://localhost:8080
服务端返回的通常不是200的状态码,而是服务端支持WebSocket的返回
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: 1qVdfYHU9hPOl4JYYNXF623Gzn0=
Sec-WebSocket-Protocol: v10.stomp
然后客户端将协议升级成为WebSocket,握手完成。
HTTP vs WebSocket
使用HTTP与其他应用程序的交互通常通过URL,服务器将请求路由到相应的处理程序是基于HTTP URL,method,和headers。
相比于HTTP, WebSockets通常只是有一个URL初始连接,随后所有应用程序消息流上同样的TCP连接。
SpringBoot 集成WebSocket Demo
1. maven 依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
2.WebSocketHandler
SpringBoot 提供两种WebSocketHandler,TextWebSocketHandler 用于处理文本信息,BinaryWebSocketHandler用于处理二进制信息。session对象表示当前连接会话,session.sendMessage(new TextMessage("send message to current user"));向当前客户端发送消息
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.TextMessage;
@Component
public class MyHandler extends TextWebSocketHandler {
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
log.info("Opened new session in instance " + this);
}
@Override
public void handleTextMessage(WebSocketSession session, TextMessage message) {
// ...
}
@Override
public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
log.info("Info: WebSocket connection closed.");
}
@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) {
}
}
3.WebSocketConfigurer
配置WebSocketHandler 映射到特定的URL,设置允许跨域,设置消息缓冲区大小,设置空闲连接超时时长
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;
import org.springframework.web.socket.server.standard.ServletServerContainerFactoryBean;
@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
@Autowired
private MyHandler myHandler;
/**
* sockJs 低版本浏览器不支持webSocket时使用
* url结构:http://host:port/{endpoint}/{server-id}/{session-id}/websocket
* 也可以: ws://host:port/{endpoint}/websocket
* <p>
* 不使用sockJs 访问时 url: ws://host:port/{endpoint}
* <p>
* setClientLibraryUrl 兼容客户端sockJs版本
*/
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(myHandler, "/myHandler").setAllowedOrigins("*");
registry.addHandler(myHandler, "/myHandler").setAllowedOrigins("*").withSockJS()
.setTaskScheduler(sockJsScheduler()).setClientLibraryUrl("//cdn.jsdelivr.net/sockjs/1/sockjs.min.js");
}
@Bean
public ServletServerContainerFactoryBean createWebSocketContainer() {
ServletServerContainerFactoryBean container = new ServletServerContainerFactoryBean();
// ws 传输数据的时候,数据过大有时候会接收不到,所以在此处设置bufferSize
container.setMaxTextMessageBufferSize(512000);
container.setMaxBinaryMessageBufferSize(512000);
container.setMaxSessionIdleTimeout(15 * 60000L);
return container;
}
}
4.WebSocket Handshake
通过集成HandshakeInterceptor,重写"before" 和 "after"的握手方法可以自定义HTTP和WebSocket的握手请求。例如,有一个内置的拦截器通过HTTP会话属性封装到WebSocket会话属性:
@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(new MyHandler(), "/myHandler")
.addInterceptors(new HttpSessionHandshakeInterceptor());
}
}
@Override
public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response,
WebSocketHandler wsHandler, Map<String, Object> attributes) throws Exception {
HttpSession session = getSession(request);
if (session != null) {
if (isCopyHttpSessionId()) {
attributes.put(HTTP_SESSION_ID_ATTR_NAME, session.getId());
}
Enumeration<String> names = session.getAttributeNames();
while (names.hasMoreElements()) {
String name = names.nextElement();
if (isCopyAllAttributes() || getAttributeNames().contains(name)) {
attributes.put(name, session.getAttribute(name));
}
}
}
return true;
}
5.Server config
每一个websocket 引擎都会暴露一些配置属性用于控制运行时的特性,比如说消息缓冲区的大小,空闲超时时长等等。
对于Tomcat来说,可以添加ServletServerContainerFactoryBean 到你的Websocket Java Config 来控制
@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
@Bean
public ServletServerContainerFactoryBean createWebSocketContainer() {
ServletServerContainerFactoryBean container = new ServletServerContainerFactoryBean();
container.setMaxTextMessageBufferSize(8192);
container.setMaxBinaryMessageBufferSize(8192);
container.setMaxSessionIdleTimeout(15 * 60000L);
return container;
}
}
网友评论