我已修改为在spring-websocket-portfolio示例应用程序(https://github.com/rstoyanchev/spring-websocket-portfolio)中实现通道拦截器。每当客户端断开连接时,通道拦截器将被处理两次。我的生产应用程序中有类似的实现。因为它被调用两次所以它对第二次调用有不需要的结果。我暂时解决了这个问题。但想知道为什么我的通道拦截器被调用两次?任何帮助都将受到高度赞赏。
修改过的项目:
WebSocketConfig.java :
@Override
public void configureClientInboundChannel(ChannelRegistration registration) {
registration.setInterceptors(channelInterceptor());
}
@Bean
public ChannelInterceptor channelInterceptor() {
return new ChannelInterceptor();
}
ChannelInterceptor :
package org.springframework.samples.portfolio.config;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.simp.stomp.StompHeaderAccessor;
import org.springframework.messaging.support.ChannelInterceptorAdapter;
public class ChannelInterceptor extends ChannelInterceptorAdapter {
@Override
public void postSend(Message<?> message, MessageChannel channel, boolean sent) {
StompHeaderAccessor sha = StompHeaderAccessor.wrap(message);
System.out.println(sha.getCommand() + " " + sha);
switch (sha.getCommand()) {
case CONNECT: {
System.out.println("connected:"+sha.getSessionId());
break;
}
case DISCONNECT: {
System.out.println("disconnected:"+sha.getSessionId());
break;
}
default:
System.out.println("default:"+sha.getCommand());
break;
}
}
}
日志:
**disconnected**:9k1hvln6
**disconnected**:9k1hvln6
答案 0 :(得分:1)
对于同一个会话,断开事件可能会多次发生,您的拦截器应该是幂等的并且忽略重复事件。
您也可以考虑使用应用程序事件(SessionConnectEvent,SessionDisconnectEvent ...)而不是频道拦截器。这是幂等事件监听器的示例:https://github.com/salmar/spring-websocket-chat/blob/master/src/main/java/com/sergialmar/wschat/event/PresenceEventListener.java
答案 1 :(得分:1)
通常,DISCONNECT帧到达客户端,在StompSubProtocolHandler中处理,然后传播到代理。但是,如果没有DISCONNECT帧,也可以关闭或丢失连接。无论连接如何关闭,StompSubProtocolMessageHandler都会生成DISCONNECT帧。因此,服务器端存在一些冗余,以确保代理知道客户端连接已消失。
正如Sergi所提到的,您可以订阅侦听SessionDisconnectEvent(其中应该只有一个)和其他AbstractSubProtocol事件,或者确保您的代码是幂等的。