当前位置: 首页 > 知识库问答 >
问题:

使用Spring和sockJS在websocket上跺脚消息丢失

邹慈
2023-03-14

在客户端javascript上,我有

    stomp.subscribe("/topic/path", function (message) {
        console.info("message received");
    });

在服务器端

public class Controller {
  private final MessageSendingOperations<String> messagingTemplate;
  @Autowired
  public Controller(MessageSendingOperations<String> messagingTemplate) {
      this.messagingTemplate = messagingTemplate;
  }
  @SubscribeMapping("/topic/path")
  public void subscribe() {
     LOGGER.info("before send");
     messagingTemplate.convertAndSend(/topic/path, "msg");
  }
}

从这个设置中,我偶尔(大约每30次页面刷新一次)会遇到消息丢失,这意味着我既看不到客户端的“message received”消息,也看不到Chrome调试工具的websocket流量。

“发送前”始终记录在服务器端。

这看起来像是当我在订阅()方法中调用MessageSending操作时,它还没有准备好。(如果我把Thread.sleep(50);在调用MessagingTemplate.convert和发送之前,问题会消失(或者不太可能重现))

我想知道以前是否有人经历过同样的情况,是否有事件可以告诉我MessageSendingOperations是否准备就绪。

共有3个答案

詹甫
2023-03-14

有点晚了,但我想我应该加上我的解决方案。在通过消息传递模板发送数据之前,我遇到了订阅未注册的相同问题。这个问题很少发生,而且是不可预测的,因为与DefaultSub换算注册表的竞争。

不幸的是,我不能仅仅使用@SubscriptionMapping的返回方法,因为我们使用的是一个自定义对象映射器,它根据用户类型(本质上是属性过滤)进行动态更改。

我搜索了Spring代码,发现SubscriptionMethodReturnValueHandler负责发送订阅映射的返回值,并且与异步控制器的autowiredSimpMessageTemplate不同的messagingTemplate!!

因此,解决方案是将MessageChannel clientOutboundChannel自动连接到我的异步控制器中,并使用它创建SimpMessagingTemplate。(您不能直接连接它,因为您只需将模板发送给代理即可)。

在订阅方法中,我使用直接模板,而在其他方法中,我使用到代理的模板。

秦权
2023-03-14

这是我的解决方案。它是沿着同样的路线。添加了一个ExecutorChannelInterceptor并发布了一个自定义的SubcriptionSub换购事件。关键是在AbstractBrokerMessageHandler处理消息后发布事件,这意味着订阅已在代理处注册。

@Override
public void configureClientInboundChannel(ChannelRegistration registration) {
    registration.interceptors(new ExecutorChannelInterceptorAdapter() {

        @Override
        public void afterMessageHandled(Message<?> message, MessageChannel channel, MessageHandler handler, Exception ex) {
            SimpMessageHeaderAccessor accessor = SimpMessageHeaderAccessor.wrap(message);
            if (accessor.getMessageType() == SimpMessageType.SUBSCRIBE && handler instanceof AbstractBrokerMessageHandler) {
                /*
                 * Publish a new session subscribed event AFTER the client
                 * has been subscribed to the broker. Before spring was
                 * publishing the event after receiving the message but not
                 * necessarily after the subscription occurred. There was a
                 * race condition because the subscription was being done on
                 * a separate thread.
                 */
                applicationEventPublisher.publishEvent(new SessionSubscribedEvent(this, message));
            }
        }
    });

}
夹谷和韵
2023-03-14

您面临的问题在于clientInboundChannel的性质,默认情况下,它是executorSubscribebalChannel

它有3个订户:

0 = {SimpleBrokerMessageHandler@5276} "SimpleBroker[DefaultSubscriptionRegistry[cache[0 destination(s)], registry[0 sessions]]]"
1 = {UserDestinationMessageHandler@5277} "UserDestinationMessageHandler[DefaultUserDestinationResolver[prefix=/user/]]"
2 = {SimpAnnotationMethodMessageHandler@5278} "SimpAnnotationMethodMessageHandler[prefixes=[/app/]]"

taskExec导师中调用,因此是异步的。

这里的第一个(SimpleBrokerMessageHandler(或StompBrokerRelayMessageHandler)如果您使用代理中继),负责注册主题订阅

在WebSocket会话的订阅注册之前,可以执行您的MessagingTemplate.convertAnd发送(/title/path,"msg")操作,因为它们是在单独的线程中执行的。因此,Broker处理程序不知道您要向会话发送消息。

可以在方法上配置返回,其中此方法的结果将作为对客户端上的订阅函数的回复发送。

 类似资料:
  • 我正在构建一个无状态Spring(4.2.4.RELEASE)解决方案,使用STOMP over Websockets和SockJS,以及使用JWT连接移动设备和全双工通信的Restendpoint。我使用Tomcat 8.0.33作为Web服务器,并使用html和sockjs javascript客户端进行测试。stomp协议使用http回退可以很好地工作,但我不能仅使用websocket协议。

  • 我使用的是Spring版本4.3.6。在服务器端和bowers客户端上发布"Stamp-webSocket":"2.0"和"Sockjs-Client":"1.1.4" 以下是服务器端的所有相关代码- 在客户机上,这是代码- Websocket connect建立后,我收到心跳消息,但没有收到我正在发送的通知。我甚至尝试过使用@SendTo注释,但它不起作用。 当我使用webjarstomp和so

  • 尝试使用Spring 4 WebSocket与STOMP通过使用Sockjs套接字。我面临一个问题。 我的配置: websocket.xml-Spring上下文的一部分 控制器代码: 客户端: 输出: 我做错了什么? 我在谷歌(TickerStocks或类似的东西,问候应用程序(Spring的例子))中找到了一些例子,所有这些都给了我同样的错误。我尝试使用WebSocket进行握手(不使用sock

  • 使用SockJS java客户机,我试图连接到Spring SockJS服务器,但对于大约20KB的消息(没有标头),错误为1009。Javascript库工作正常。 还必须将Java SockJS客户端配置为接收更大的消息。 或者,服务器上的配置仍然错误。 如何在Java SockJS Spring客户机上增加缓冲区大小?

  • 我们正在将SpringWebSockets集成到我们的应用程序中,我运行了HelloWorld示例,令人惊讶的是,spring为我们连接了一切,以便将服务器端通知推送到客户端。 不过,我有一些简单的问题 1) 队列是如何创建的?我使用的是ActiveMQ,队列名称与我在目的地中指定的不同(例如,像greetings-user3n9\u jn3i)。 2)目标名称是否不同于队列? 3) 我正在使用A

  • 问题内容: 如何仅从服务器向特定用户发送websocket消息? 我的webapp具有spring安全设置,并使用websocket。我在尝试仅从服务器向特定用户发送消息时遇到棘手的问题。 通过阅读手册,我的理解是来自我们可以做的服务器 在客户端: 但是我永远无法调用订阅回调。我尝试了许多不同的方法,但是没有运气。 如果我将其发送到/ topic / reply,它可以工作,但所有其他已连接用户也