为了通过 STOMP 协议的 WebSocket 实现传输长字符串(如超过 1MB 的消息),我们需要从前端到后端的多个方面进行配置和优化,包括心跳检测、消息分块、Tomcat 超时设置等。以下是一个完整的方案,涵盖前端和后端的配置,以及长字符串的传输处理。
方案要点:
- 前端分块传输大字符串:WebSocket 可能对单条消息大小有限制,因此需要将大字符串分块传输。
- 心跳检测:通过心跳检测来保持 WebSocket 连接的活跃性,防止长时间无消息传输时连接断开。
- Tomcat 配置:确保 Tomcat 的连接超时时间超过心跳间隔,避免因超时导致的连接断开。
- 自动重连机制:在连接断开时自动重连,确保连接的稳定性。
- 代理服务器配置:如果有代理服务器(如 NGINX),确保配置允许长时间连接和大消息传输。
完整方案:
1. 前端:分块传输长字符串,心跳检测和自动重连
为了确保前端能够稳定地发送大消息(如超过 1MB 的字符串),我们可以将大消息分块,每次发送一个较小的块(如 128KB),并通过心跳机制保持连接的活跃性。如果连接断开,前端可以自动尝试重连。
前端代码:
<script src="https://cdnjs.cloudflare.com/ajax/libs/stomp.js/2.3.3/stomp.min.js"></script>
<script src="https://cdn.jsdelivr.net/sockjs/1.5.1/sockjs.min.js"></script><script>// 启动 WebSocket 连接并启用心跳检测和自动重连function connect() {const socket = new SockJS('http://your-server-address/ws');const stompClient = Stomp.over(socket);// 启用心跳检测,每10秒发送/接收心跳stompClient.connect({}, function(frame) {console.log('Connected: ' + frame);}, function(error) {console.log('Connection lost, retrying...');setTimeout(connect, 5000); // 5秒后自动重连}, {heartbeatIncoming: 10000, // 每10秒接收心跳heartbeatOutgoing: 10000 // 每10秒发送心跳});// 分块发送大字符串function sendLargeData(stompClient, destination, message) {const chunkSize = 128 * 1024; // 每块128KBlet offset = 0;// 分块发送消息while (offset < message.length) {const chunk = message.substring(offset, offset + chunkSize);stompClient.send(destination, {}, chunk); // 发送每块数据offset += chunkSize;}}// 示例:模拟发送1MB以上的大消息const largeMessage = 'A'.repeat(1024 * 1024 + 100); // 创建超过1MB的字符串sendLargeData(stompClient, "/app/destination", largeMessage);}// 启动连接connect();
</script>
2. 后端:Spring Boot WebSocket 和 STOMP 配置
在 Spring Boot 中,通过 WebSocket 和 STOMP 实现消息的接收和处理,并启用心跳检测,确保长时间保持连接。
后端配置(WebSocketConfig.java
):
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {@Overridepublic void configureMessageBroker(MessageBrokerRegistry config) {// 配置简单消息代理,并设置心跳机制config.enableSimpleBroker("/topic", "/queue").setHeartbeatValue(new long[]{10000, 10000}); // 每10秒发送和接收心跳config.setApplicationDestinationPrefixes("/app");}@Overridepublic void registerStompEndpoints(StompEndpointRegistry registry) {// 配置STOMP终端,允许跨域并启用SockJS支持registry.addEndpoint("/ws").setAllowedOrigins("*").withSockJS();}@Overridepublic void configureWebSocketTransport(WebSocketTransportRegistration registration) {registration.setMessageSizeLimit(5 * 1024 * 1024); // 设置最大消息大小为5MBregistration.setSendBufferSizeLimit(10 * 1024 * 1024); // 设置发送缓冲区为10MBregistration.setSendTimeLimit(20000); // 设置发送时间限制为20秒}// 配置心跳调度器public TaskScheduler heartBeatScheduler() {ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();scheduler.setPoolSize(1);scheduler.setThreadNamePrefix("wss-heartbeat-thread-");scheduler.initialize();return scheduler;}
}
3. Tomcat 超时配置
确保 Tomcat 的连接超时时间大于心跳间隔时间,以防止连接过早断开。假设心跳间隔为 10 秒,我们可以将连接超时时间设置为 30 秒或更长。
在 application.properties
中配置:
# 设置Tomcat的连接超时时间为30秒
server.tomcat.connection-timeout=30000
在 server.xml
文件中配置(如果使用独立的 Tomcat):
<Connector port="8080" protocol="HTTP/1.1"connectionTimeout="30000" <!-- 30秒超时 -->redirectPort="8443" />
4. 代理服务器(NGINX)配置
如果你使用 NGINX 作为代理服务器,确保 NGINX 的超时配置允许长时间的 WebSocket 连接。增加 proxy_read_timeout
和 proxy_send_timeout
。
NGINX 配置示例:
http {client_max_body_size 10M; # 允许传输最大消息体10MBproxy_read_timeout 3600s; # 允许长时间的连接读取proxy_send_timeout 3600s; # 允许长时间的连接发送server {listen 80;location /ws {proxy_pass http://backend-server;proxy_http_version 1.1;proxy_set_header Upgrade $http_upgrade;proxy_set_header Connection $connection_upgrade;}}
}
5. 处理大消息的性能优化
在处理大消息时,除了网络传输问题,后端的性能优化也很重要。确保处理长消息时,服务器有足够的资源处理高并发请求,可以通过调整线程池大小、增加内存等方式进行优化。
增加 Spring Boot 中线程池大小:
server.tomcat.max-threads=300 # 增加Tomcat最大线程数
总结
通过这个完整的方案,你可以通过 STOMP 协议的 WebSocket 实现长字符串(超过 1MB)的稳定传输。关键点包括:
- 前端分块传输:将大字符串分块传输,避免单次传输过大。
- 心跳检测:通过前后端心跳配置,保持连接的活跃性。
- Tomcat 超时配置:确保 Tomcat 的连接超时时间大于心跳间隔时间。
- 代理服务器配置:如果使用 NGINX,确保代理服务器允许长时间的 WebSocket 连接。
- 性能优化:通过配置合适的线程池和资源来确保高并发和大消息处理。
通过以上优化,能够确保 WebSocket 长时间稳定连接,并顺利处理大数据传输。