Cometd javascript client doesn't subscribe to

2019-08-30 18:52发布

问题:

It seems that the javascript client cannot subscribe to the broadcast channel or receive the message from it. Below is the spring-cometd service code that broadcast the message on the notification channel after receiving message from external event. The java-cometd client can receive the broadcast messages sucessfuly. Even the javascript client can publish and subscribe the messages on service channels but not on broadcast channel. The subscription is done after the handshake.

JavaScript Code:

  var cometd = $.cometd;



  cometd.addListener('/meta/handshake', _metaHandshake);// handshake listener
        cometd.addListener('/meta/connect', _metaConnect);//connection connect listener
        cometd.addListener('/meta/disconnect', _metaDisconnect); 
        cometd.handshake();



  function _metaHandshake(handshake)
            {
                if (handshake.successful === true)  
                {


                    cometd.batch(function()
                    {


                cometd.subscribe('/notification', function(m) {alert("hi"); });



                    });
                }

What could go wrong when javascript client subscribe to the broadcast channel.

@javax.inject.Named // Tells Spring that this is a bean
@javax.inject.Singleton // Tells Spring that this is a singleton
@Service("notificationService")
public class NotificationService {

    private static final String channelName="/notification";
    private static ServerChannel serverChannel;
    private Logger logger = Logger.getLogger(this.getClass());

    @Inject
    private BayeuxServer bayeuxServer;

    @Session
    private LocalSession session;



    @PostConstruct
    public void init()
    {
        logger.debug("Notification Service Initialized");
        channelSetUp();
        session = bayeuxServer.newLocalSession("external");
        session.handshake();

    }


    public void channelSetUp()
    {

        MarkedReference<ServerChannel> channelCreated = bayeuxServer.createChannelIfAbsent(channelName, new ServerChannel.Initializer()
        {
        public void configureChannel(ConfigurableServerChannel channel)
        {
            channel.setPersistent(true);// channel persistent
            channel.addAuthorizer(GrantAuthorizer.GRANT_SUBSCRIBE_PUBLISH); 
        }
        });

        if(channelCreated.isMarked())
        {
            serverChannel = bayeuxServer.getChannel(channelName);

        }
    }






    public void onExternalEvent( Map<String, Object> data)
    {


        // ServerChannel serverChannel = this.bayeuxServer.getChannel(channelName);

    // logger.debug("Notify MessageData from JMS ::" + data.toString());
    if (serverChannel != null)
        {
           // Broadcast the data
        serverChannel.publish(session, data, null);

        }


    }



    @Listener(Channel.META_SUBSCRIBE)  
    public void processSubscription(ServerSession remote, ServerMessage message)
    {   
        // What channel the client wants to subscribe to ?
       String channel = (String)message.get(Message.SUBSCRIPTION_FIELD);
       logger.debug("Client Channel ::"+channel);

    }




}

回答1:

Your client code is correct.

Your server code can be improved, in particular:

  • You don't need to create a local session in init(): the @Session annotation does it for you.
  • You don't need to call channelSetup() in init(): just use a @Configure annotation.
  • You don't need to store a reference to the ServerChannel: since you made the channel persistent, in onExternalEvent() just do: bayeuxServer.getChannel(channelName).publish(...);

If you have followed correctly the documentation for the Spring integration, and avoided the creation of 2 BayeuxServer instances (a typical error when using Spring) described in the documentation, then you should be good to go.

I suggest that you enable debug logging in both client and server, and look at the logs, that should explain why your JavaScript client does not receive the messages.

Hope that helped !