WebSocket 消息并非始终传递
WebSocket messages are not delivered all the times
我有一个使用 WebSockets 的应用程序,使用 spring-boot 应用程序作为后端,Stomp/SockJS 在客户端,spring-boot 应用程序使用 JMS 队列消息并通知更改给正确的用户。问题是什么?有时有效,有时无效,相同的代码和用户可能有效或无效。
客户端代码有点难以复制到这里,因为它集成在 react/redux 应用程序上,但基本上是对两个不同频道的订阅,都在 Spring 的配置中定义。会话是根据调试信息正确创建的,但有时会处理消息以将其发送到连接的会话。
这是 Spring 的配置 class。
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfiguration implements WebSocketMessageBrokerConfigurer {
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry
.addEndpoint("/stomp")
.setAllowedOrigins("*")
.withSockJS();
}
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry
.setApplicationDestinationPrefixes("/app")
.enableSimpleBroker("/xxxx/yyyy", "/ccccc");
}
@Override
public void configureClientInboundChannel(ChannelRegistration registration) {
registration.interceptors(new ChannelInterceptor() {
@Override
public Message<?> preSend(Message<?> message, MessageChannel channel) {
StompHeaderAccessor accessor =
MessageHeaderAccessor.getAccessor(message, StompHeaderAccessor.class);
if (StompCommand.CONNECT.equals(accessor.getCommand())) {
Object raw = message
.getHeaders()
.get(SimpMessageHeaderAccessor.NATIVE_HEADERS);
if (raw instanceof Map) {
Object name = ((Map<?,?>) raw).get("email");
if (name instanceof LinkedList) {
String user = ((LinkedList<?>) name).get(0).toString();
accessor.setUser(new User(user));
}
}
}
return message;
}
});
}
}
这是 JMS 侦听器,用于处理队列消息并将其发送给特定用户。
@Component
public class UserEventListener {
private final Logger logger = LoggerFactory.getLogger(getClass());
private final SimpMessagingTemplate template;
@Autowired
public UserEventListener(SimpMessagingTemplate pTemplate) {
this.template = pTemplate;
}
@JmsListener(destination="user/events")
public void onStatusChange(Map<String, Object> props) {
if (props.containsKey("userEmail")) {
logger.debug("Event for user received: {}", props.get("userEmail"));
template.convertAndSendToUser((String)props.get("userEmail"), "/ccccc", props);
}
}
}
编辑 1:
经过更多调试后,WebSocket 的 "session" 似乎被 Spring 配置丢失了。我没有看到任何关于 "Disconnected" 消息或类似信息的日志信息,此外,如果我在发生这种情况时远程调试服务器,则在调试会话期间不会出现问题。一些想法?会话消失的 Spring 中的 class 是 DefaultSimpUserRegistry
。
经过更多研究,我发现了一个具有相同问题和解决方案的问题 。基本上结论是这样的:
通道拦截器不是验证用户的正确位置,我们需要使用自定义握手处理程序来更改它。
我有一个使用 WebSockets 的应用程序,使用 spring-boot 应用程序作为后端,Stomp/SockJS 在客户端,spring-boot 应用程序使用 JMS 队列消息并通知更改给正确的用户。问题是什么?有时有效,有时无效,相同的代码和用户可能有效或无效。
客户端代码有点难以复制到这里,因为它集成在 react/redux 应用程序上,但基本上是对两个不同频道的订阅,都在 Spring 的配置中定义。会话是根据调试信息正确创建的,但有时会处理消息以将其发送到连接的会话。
这是 Spring 的配置 class。
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfiguration implements WebSocketMessageBrokerConfigurer {
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry
.addEndpoint("/stomp")
.setAllowedOrigins("*")
.withSockJS();
}
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry
.setApplicationDestinationPrefixes("/app")
.enableSimpleBroker("/xxxx/yyyy", "/ccccc");
}
@Override
public void configureClientInboundChannel(ChannelRegistration registration) {
registration.interceptors(new ChannelInterceptor() {
@Override
public Message<?> preSend(Message<?> message, MessageChannel channel) {
StompHeaderAccessor accessor =
MessageHeaderAccessor.getAccessor(message, StompHeaderAccessor.class);
if (StompCommand.CONNECT.equals(accessor.getCommand())) {
Object raw = message
.getHeaders()
.get(SimpMessageHeaderAccessor.NATIVE_HEADERS);
if (raw instanceof Map) {
Object name = ((Map<?,?>) raw).get("email");
if (name instanceof LinkedList) {
String user = ((LinkedList<?>) name).get(0).toString();
accessor.setUser(new User(user));
}
}
}
return message;
}
});
}
}
这是 JMS 侦听器,用于处理队列消息并将其发送给特定用户。
@Component
public class UserEventListener {
private final Logger logger = LoggerFactory.getLogger(getClass());
private final SimpMessagingTemplate template;
@Autowired
public UserEventListener(SimpMessagingTemplate pTemplate) {
this.template = pTemplate;
}
@JmsListener(destination="user/events")
public void onStatusChange(Map<String, Object> props) {
if (props.containsKey("userEmail")) {
logger.debug("Event for user received: {}", props.get("userEmail"));
template.convertAndSendToUser((String)props.get("userEmail"), "/ccccc", props);
}
}
}
编辑 1:
经过更多调试后,WebSocket 的 "session" 似乎被 Spring 配置丢失了。我没有看到任何关于 "Disconnected" 消息或类似信息的日志信息,此外,如果我在发生这种情况时远程调试服务器,则在调试会话期间不会出现问题。一些想法?会话消失的 Spring 中的 class 是 DefaultSimpUserRegistry
。
经过更多研究,我发现了一个具有相同问题和解决方案的问题
通道拦截器不是验证用户的正确位置,我们需要使用自定义握手处理程序来更改它。