在春季启动从1.2.0升级到2.1.3之后,Websocket推送通知不起作用

时间:2019-07-29 17:02:35

标签: spring spring-boot websocket spring-websocket stomp

这是关于使用 websocket + stompjs 发送推送通知的spring 启动 + angularjs Web应用程序。

我最近从Spring Boot 1.2.0升级到2.1.3 之前,此升级网络套接字(推送通知)可以正常工作几年

我刚刚升级了Spring Boot,并且与Websocket相关的代码仍然完全相同,但是现在正在工作。

不起作用表示:

  1. 在服务器端执行的下一行没有任何错误/异常。

simpMessagingTemplate.convertAndSend("/topic/notify", payload);

  1. Chrome 调试器仅接收“ h”(心跳),而不接收实际消息。

不知道,因为

  • 服务器端代码成功执行直到最后一行
  • 建立了
  • websocket会话,我可以获得心跳消息,但在客户端也没有错误。

代码(但相同的代码在Spring boot 1.2.0中也能很好地工作:

1。配置:

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {

    @Value("${server.sessionTimeout}")
    long sessionTimeoutInSecs;

    @Override
    public void configureMessageBroker(MessageBrokerRegistry config) {
        config.enableSimpleBroker("/topic");
        config.setApplicationDestinationPrefixes("/app");
    }

    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/notify").withSockJS();
    }

    @Bean
    public ServletServerContainerFactoryBean createWebSocketContainer() {
        ServletServerContainerFactoryBean container = new ServletServerContainerFactoryBean();
        // in milliseconds
        container.setMaxSessionIdleTimeout(sessionTimeoutInSecs * 1000);
        return container;
    }
}

2。邮件发送代码:

simpMessagingTemplate.convertAndSend("/topic/notify", payload);

3。客户代码:

(function() {
  myApp.factory('autoUpdateTasksService', function($resource, $q, $log) {
    var initSockets, notify, reconnect, socket, _callback;
    _callback = null;
    socket = {
      client: null,
      stomp: null
    };
    initSockets = function() {
      socket.client = new SockJS('/notify');
      socket.stomp = Stomp.over(socket.client);
      socket.stomp.connect({}, function() {});
      socket.client.onopen = function() {
        var subscription1;
        subscription1 = socket.stomp.subscribe("/topic/notify", notify);
        //$log.log('socket connected');
      };
    };
    reconnect = function() {
      setTimeout(initSockets, 1000);
    };
    notify = function(message) {
         try{
              var taskNotifyObject;
                  if (message.body) {
                    taskNotifyObject = angular.fromJson(message.body);
                    //$log.log(taskNotifyObject);
                    var notificationArray=[];
                    notificationArray.push(taskNotifyObject);
                    _callback(notificationArray);
                  } else {
                    //$log.log("empty message");
                  }
             } catch(e){
                // alert(e.message); 
                 }
                };
            return {
              init: function(callback) {
                _callback = callback;
                initSockets();
              }
            };
  });

}).call(this);

Spring框架之间的版本之间有什么变化吗?

如何调试/查找丢失消息的位置?

1 个答案:

答案 0 :(得分:0)

根本原因::升级后,我问题中的代码无法在服务器和客户端之间建立连接(未能创建 websocketSession

更改代码,可以解决以下问题,但我确定为什么该解决方案有效,

如果有人解释为什么,该解决方案有效,将会有很大帮助。

1。配置:

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {

    @Value("${server.servlet.session.timeout}")
    long sessionTimeoutInSecs;

    @Override
    public void configureMessageBroker(MessageBrokerRegistry config) {
        config.enableSimpleBroker("/queue");
        config.setApplicationDestinationPrefixes("/app");
    }

    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/notify").addInterceptors(new HttpSessionHandshakeInterceptor());
    }

    @Bean
    public ServletServerContainerFactoryBean createWebSocketContainer() {
        ServletServerContainerFactoryBean container = new ServletServerContainerFactoryBean();
        // in milliseconds
        container.setMaxSessionIdleTimeout(sessionTimeoutInSecs * 1000);
        return container;
    }

    /**
     * DefaultSimpUserRegistry is the replacement of MySessionRegistry ( Custom UserSessionRegistry ) after upgrade to Spring 5.
     * Below required with Spring 4.
     * import org.springframework.messaging.simp.user.UserSessionRegistry;
        @Repository
        public class MySessionRegistry implements UserSessionRegistry, ApplicationListener<AbstractSubProtocolEvent> {
     * 
     */ 
    @Bean
    public DefaultSimpUserRegistry defaultSimpUserRegistry() {
        DefaultSimpUserRegistry userRegistry = new DefaultSimpUserRegistry();
        return userRegistry;
    }
}

2。邮件发送代码:

import org.springframework.web.socket.messaging.DefaultSimpUserRegistry;

@Autowired
DefaultSimpUserRegistry defaultSimpUserRegistry;

.....

SimpUser simpUser = defaultSimpUserRegistry.getUser(payload.getUserName());

if(simpUser != null && simpUser.hasSessions()) {
     template.convertAndSendToUser(payload.getUserName(), "/queue/notify", payload);
}

3。客户代码:

(function() {
  myApp.factory('autoUpdateTasksService', function($resource, $q, $log) {
    var initSockets, notify, reconnect, socket, _callback;
    _callback = null;
    socket = {
      client: null,
      stomp: null
    };
    getContextPath = function() {
        return window.location.pathname.substring(0, window.location.pathname.indexOf("/",2));
    };
    initSockets = function() {
        //socket.addr = "wss://" + window.location.host + "/notify";
        socket.addr = ((window.location.protocol && (window.location.protocol.indexOf("https") >= 0)) ? "wss://" : "ws://") + window.location.host + getContextPath() + "/notify";
        socket.client = Stomp.client(socket.addr); //new SockJS('/notify');
        socket.client.connect({}, function () {
          $log.log("Connected to websocket through " + socket.addr);
          socket.client.subscribe("/user/queue/notify", notify);
        }, function (err) {
          $log.log("Error when connection to websocket " + socket.addr + ".\n" + err);
        });
    };
  

如何调试/查找消息丢失的地方?

要验证客户端与服务器的连接(或创建websocketSession),我在监听器下面添加了内容。

import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.messaging.simp.stomp.StompHeaderAccessor;
import org.springframework.web.socket.messaging.SessionConnectedEvent;
import org.springframework.web.socket.messaging.SessionSubscribeEvent;

@Component
public class WebSocketListener implements ApplicationListener <ApplicationEvent> {

            //WebSocket session created
            if (appEvent instanceof SessionConnectedEvent){
                StompHeaderAccessor sha = StompHeaderAccessor.wrap(((SessionConnectedEvent) appEvent).getMessage());
                logger.info("SessionConnectedEvent: STOMP WebSocket session created for the user: {}", sha.getUser().getName());
            }

            //subscribed to websocketSession
            if (appEvent instanceof SessionSubscribeEvent){
                StompHeaderAccessor sha = StompHeaderAccessor.wrap(((SessionSubscribeEvent) appEvent).getMessage());                
                logger.info("SessionSubscribeEvent: User {} subscribed to WebSocket session, destination: {}", sha.getUser().getName(), sha.getDestination());
            }
//            
//            if (appEvent instanceof BrokerAvailabilityEvent){
//                logger.info("BrokerAvailabilityEvent: {}", appEvent.toString());
//            }
        }
}