我们有一个Spring over WebSockets连接,我们正在传递一个CONNECT
帧:
CONNECT\naccept-version:1.2\nheart-beat:10000,10000\n\n\u0000
处理程序确认,启动一个新会话,然后than返回:
CONNECTED
version:1.2
heart-beat:0,0
但是,我们需要心跳,这样我们就可以保持WebSocket打开。我们没有使用SockJS。
我逐步完成了Spring消息处理程序:
StompHeaderAccessor [headers={simpMessageType=CONNECT, stompCommand=CONNECT, nativeHeaders={accept-version=[1.2], heart-beat=[5000,0]}, simpSessionAttributes={}, simpHeartbeat=[J@5eba717, simpSessionId=46e855c9}]
获取心跳
(本机头)后,它设置看起来像内存地址的内容simpHeartbeat=[J@5eba717, simpSessionId=46e855c9}]
值得注意的是,在经纪人进行身份验证后:
处理CONNECT会话=46e855c9
(这里的session sionId不同于simpSessionId)?
在运行之前的TRACE
调试时,我看到了一个通知“调度心跳……”或类似的东西……虽然我现在没有看到它?
知道是怎么回事吗?
谢啦
我在留档中找到了解释:
SockJS Task Scheduler来自用于发送心跳的SockJS任务调度器的线程池的统计信息。请注意,当在STOMP级别协商心跳时,SockJS心跳将被禁用。
SockJS心跳与STOMP心跳不同吗?
从Spring 4.2开始,您可以使用Stomp over SockJS和内置的SimpleBroker从服务器端完全控制心跳协商结果:
public class WebSocketConfigurer extends AbstractWebSocketMessageBrokerConfigurer {
@Override
public void configureMessageBroker(MessageBrokerRegistry config) {
ThreadPoolTaskScheduler te = new ThreadPoolTaskScheduler();
te.setPoolSize(1);
te.setThreadNamePrefix("wss-heartbeat-thread-");
te.initialize();
config.enableSimpleBroker("/")
/**
* Configure the value for the heartbeat settings. The first number
* represents how often the server will write or send a heartbeat.
* The second is how often the client should write. 0 means no heartbeats.
* <p>By default this is set to "0, 0" unless the {@link #setTaskScheduler
* taskScheduler} in which case the default becomes "10000,10000"
* (in milliseconds).
* @since 4.2
*/
.setHeartbeatValue(new long[]{heartbeatServer, heartbeatClient})
.setTaskScheduler(te);
}
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint(.....)
.setAllowedOrigins(....)
.withSockJS();
}
}
是的,SockJS心跳是不同的。基本上是一样的,但它们在SockJS协议中的目的是确保连接看起来不像是“死”的,在这种情况下,代理可以主动关闭它。更一般地说,心跳允许每一方主动检测连接问题并清理资源。
在传输层使用STOMP和SockJS时,不需要两者兼而有之,这就是为什么如果使用STOMP心跳,SockJS心跳会被关闭。但是你在这里没有使用SockJS。
你没有显示任何配置,但我猜你使用的是内置的简单代理,它不会自动发送心跳。配置它时,你会看到一个启用心跳的选项,你还需要设置一个任务调度程序。
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
// ...
}
@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.enableStompBrokerRelay(...)
.setTaskScheduler(...)
.setHeartbeat(...);
}
}
我们在Spring、Websocket、STOMP和Spring Ssession上遇到了同样的问题——当websocket在服务器端没有接收消息时,没有心跳,Spring会话可能会过期。我们最终每20000ms从浏览器启用STOMP心跳,并将SimpMessageType. HEARTBEAT添加到Spring session sionRepositoryInterceptor匹配中,以保持Spring会话上次访问时间在没有消息的STOMP心跳上更新。我们必须使用AbstractSessionWebSocketMessageBrokerConfirer作为基础来启用内置Spring会话和websocket会话绑定。Spring手册,第二个例子。在官方示例中,Spring会话在入站websocket CONNECT/MESSAGE/SUBSCRIBE/UNSUBSCRIBE消息上更新,但不是心跳,这就是为什么我们需要重新配置两件事-至少启用入站心跳并调整Spring会话以响应websocket心跳
public class WebSocketConfig extends AbstractSessionWebSocketMessageBrokerConfigurer<ExpiringSession> {
@Autowired
SessionRepositoryMessageInterceptor sessionRepositoryInterceptor;
@Override
public void configureMessageBroker(MessageBrokerRegistry config) {
sessionRepositoryInterceptor.setMatchingMessageTypes(EnumSet.of(SimpMessageType.CONNECT,
SimpMessageType.MESSAGE, SimpMessageType.SUBSCRIBE,
SimpMessageType.UNSUBSCRIBE, SimpMessageType.HEARTBEAT));
config.setApplicationDestinationPrefixes(...);
config.enableSimpleBroker(...)
.setTaskScheduler(new DefaultManagedTaskScheduler())
.setHeartbeatValue(new long[]{0,20000});
}
}
我们尝试的另一种方法是重新实现SessionRepositoryMessageInterceptor功能以更新出站websocket消息上的Spring会话最后访问时间以及维护websocket会话-