Search code examples
javaspring-bootspring-websocket

Spring WebSocketMessageBroker - Cannot send messages longer than 64KB, and cannot increase limit via configuration


I have an app with a front-end in React and back-end in Java & Spring Boot.

The front-end subscribes to many topics via websockets, and it always goes fine, except when the messages are too long. It turns out, when the websocket message is longer than 64KB, the message is not sent, but no error is reported. Plus, any subsequent attempts to send more messages on that connection, even if the message is short, are also lost.

On the back-end, first we configure the websocket. I tried the suggestions of other answers that say to increase size limits: here and here, but none of them worked. It seems that those values are ignored altogether, as if I set a ridiculously low value, longer messages can still go through (if less than 64K).

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
    @Override
    public void configureMessageBroker(MessageBrokerRegistry config)
    {
        config.enableSimpleBroker("/ws");
    }
    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry)
    {
        registry.addEndpoint("/ws").setAllowedOriginPatterns("*").withSockJS();
    }

    @Override
    public void configureWebSocketTransport(WebSocketTransportRegistration registry)
    {
        registry.setMessageSizeLimit(1000000);
        registry.setSendBufferSizeLimit(1000000);
        registry.setSendTimeLimit(100000);
    }
}

Here is a simplified example that sends the websocket messages, that I have also tested and continues to have the same issue. Just calling an HTTP endpoint from the application so it will trigger the notification.

@RestController
@RequestMapping("/greeting")
public class GreetingController {

    @Autowired
    private SimpMessagingTemplate messageTemplate;
    
    @GetMapping("/{length}")
    public ResponseEntity<?> sendGreeting(@PathVariable int length)
    {
        String destination = "/ws/subscribedGreeting";
        
        char[] charArray = new char[length];
        Arrays.fill(charArray, '*');
        String messageString = new String(charArray);
        
        messageTemplate.convertAndSend(destination, messageString);

        return ResponseEntity.noContent().build();
    }
}

And sample code in the front-end:

import SockJS        from 'sockjs-client';
import Stomp         from 'stomp-websocket';

...

useEffect(() => {
  const sock        = new SockJS('my-ws-url'); // replace depending on your environment
  const stompClient = Stomp.over(sock);

  stompClient.connect({}, () => {
    stompClient.subscribe('/ws/subscribedGreeting', (messageFromSocket) => {
      console.log(`Message! ${messageFromSocket.body.length}`);
    });
  });
}, []);

And finally, make calls to the /greeting/{length} endpoint. I just did it with Postman for quick testing.

Works well (logs to console the length) if I call with low length values: /greeting/100, /greeting/10000, /greeting/60000, but if I set greeting/70000, the message is not received and any further calls will not work (but it's OK for any new subscriptions). The worst part is that there are no logs of any sort reporting a problem.

I have been looking for alternatives for a couple of days now but have not found any answer.

Any ideas? How is it that the values I configured do not work? Perhaps there is an alternate way to set the size limits?

Thanks in advance.


Solution

  • I had not realized, I was using a "gateway" component, and that is where the maximum payload was configured by default to 64K. By setting the property like in this answer I was able to fix the issue.