简体   繁体   中英

STOMP Spring WebSocket message exceeds size limit

I am implementing Spring WebSocket into our Spring MVC web application. However I am running into message over size limits when I am trying to send a really big message to an endpoint.

I am getting the following error:

message:The 'content-length' header 68718  exceeds the configured message buffer size limit 65536

14:49:11,506 ERROR [org.springframework.web.socket.messaging.StompSubProtocolHandler] (http-localhost/127.0.0.1:8080-4) Failed to parse TextMessage payload=[13684590},..], byteCount=16384, last=true] in session vlsxdeol. Sending STOMP ERROR to client.: org.springframework.messaging.simp.stomp.StompConversionException: The 'content-length' header 68718  exceeds the configured message buffer size limit 65536
at org.springframework.messaging.simp.stomp.BufferingStompDecoder.checkBufferLimits(BufferingStompDecoder.java:148) [spring-messaging-4.1.6.RELEASE.jar:4.1.6.RELEASE]
at org.springframework.messaging.simp.stomp.BufferingStompDecoder.decode(BufferingStompDecoder.java:124) [spring-messaging-4.1.6.RELEASE.jar:4.1.6.RELEASE]

Here is my configuration:

@MessageMapping("/user/sockettest" )
@SendTo("/topic/sockettestresult")
public String sockAdd(ListId[] listIds) {
..
SecurityContextHolder.getContext().getAuthentication().getPrincipal();

return stringRet;
}

The xml config looks like the following:

<websocket:stomp-endpoint path="/user/sockettest">
<websocket:sockjs/>
</websocket:stomp-endpoint>

<websocket:simple-broker prefix="/topic"/>

<websocket:message-converters register-defaults="false">
    <bean id="mappingJackson2MessageConverter" class="org.springframework.messaging.converter.MappingJackson2MessageConverter">
        <property name="objectMapper" ref="objectMapper"></property>
    </bean>
</websocket:message-converters>
</websocket:message-broker>

The client side code looks like this:

function versionFiles() {
        stompClient.send("/testbrkr/user/sockettest", {}, JSON.stringify(listIds));
    }

Can you let me know what would be a good work-around?

Answer : If you know what would be the maximum size limit

 <websocket:transport message-size="75536" send-buffer-size="75536"></websocket:transport>

I am looking on how to do partial messaging, will post it here as soon as I find out and get it working

Consider <websocket:transport message-size=""/> option for the <websocket:message-broker> definition:

Configure the maximum size for an incoming sub-protocol message. For example a STOMP message may be received as multiple WebSocket messages or multiple HTTP POST requests when SockJS fallback options are in use.

The same can be achieved in annotation configuration using WebSocketMessageBrokerConfigurer.configureWebSocketTransport(WebSocketTransportRegistration) implementation and with the setMessageSizeLimit() on the matter.

I was getting similar javascript errorr when the default value of 65kb was set.. then i set it to some random and again got some error like the

connection was interrupted

. So tried increasing the time limit and that worked for me. Actually when the limit exceeds, the messages are sent into packets/or frames, and while it was receiving the response from server, it timed out.

You can use tweak it as below

@EnableWebSocketMessageBroker
public class AppWebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
----
---
    @Override
        public void configureWebSocketTransport(WebSocketTransportRegistration registration) {
            registration.setMessageSizeLimit(200000); // default : 64 * 1024
            registration.setSendTimeLimit(20 * 10000); // default : 10 * 10000
            registration.setSendBufferSizeLimit(3* 512 * 1024); // default : 512 * 1024

        }
---
}
        List<Transport> transports = new ArrayList<Transport>();
        WebSocketContainer container = ContainerProvider.getWebSocketContainer();
        container.setDefaultMaxTextMessageBufferSize(512*1024);  //FIX
        WebSocketClient wsClient = new StandardWebSocketClient(container);
        transports.add(new WebSocketTransport(wsClient));
//      transports.add(new RestTemplateXhrTransport());

        SockJsClient sockJsClient = new SockJsClient(transports);
        WebSocketStompClient stompClient = new WebSocketStompClient(sockJsClient);
        stompClient.setMessageConverter(new SimpleMessageConverter());
        stompClient.setInboundMessageSizeLimit(512 * 1024);      //FIX


Lines commented as FIX resolved the issue for me.


I've faced the same issue and solved by configuring WebSocketTransportRegistration and ServletServerContainerFactoryBean.

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.config.annotation.AbstractWebSocketMessageBrokerConfigurer;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
import org.springframework.web.socket.config.annotation.WebSocketTransportRegistration;
import org.springframework.web.socket.server.standard.ServletServerContainerFactoryBean;

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {

    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/echo").setAllowedOrigins("*");
    }

    @Override
    public void configureWebSocketTransport(WebSocketTransportRegistration registration) {
        registration.setMessageSizeLimit(2048 * 2048);
        registration.setSendBufferSizeLimit(2048 * 2048);
        registration.setSendTimeLimit(2048 * 2048);
    }

    @Bean
    public ServletServerContainerFactoryBean createServletServerContainerFactoryBean() {
        ServletServerContainerFactoryBean factoryBean = new ServletServerContainerFactoryBean();
        factoryBean.setMaxTextMessageBufferSize(2048 * 2048);
        factoryBean.setMaxBinaryMessageBufferSize(2048 * 2048);
        factoryBean.setMaxSessionIdleTimeout(2048L * 2048L);
        factoryBean.setAsyncSendTimeout(2048L * 2048L);
        return factoryBean;
    }
}

Consider <websocket:transport message-size=""/> option for the <websocket:message-broker> definition:

Configure the maximum size for an incoming sub-protocol message. For example a STOMP message may be received as multiple WebSocket messages or multiple HTTP POST requests when SockJS fallback options are in use.

The same can be achieved in annotation configuration using

WebSocketMessageBrokerConfigurer.configureWebSocketTransport(WebSocketTransportRegistration) 

implementation and with the setMessageSizeLimit() on the matter.

This is right but... If you are using Spring WebSocket then the stomp message is

StompSubProtocolHandler

and

@Override
    public void afterSessionStarted(WebSocketSession session, MessageChannel outputChannel) {
        if (session.getTextMessageSizeLimit() < MINIMUM_WEBSOCKET_MESSAGE_SIZE) {
            session.setTextMessageSizeLimit(MINIMUM_WEBSOCKET_MESSAGE_SIZE);
        }
        this.decoders.put(session.getId(), new BufferingStompDecoder(this.stompDecoder, getMessageSizeLimit()));
    }

so here is the spring bug message size is set as websocket:transport message-size but the WebSocketSession is not ... is 8KB and this method will double it. No as the message that we want to send.

I do not know how to fix that; You need to set WebSocketSession TextMessageSizeLimit . Maybe someone how know better spring boot factory knows a spring way to change the WebSocketSession textMessageSizeLimit . Anyway I did with Aop DelegatingIntroductionInterceptor

in the WebSocketMessageBrokerConfigurer

 @Override
    public void configureWebSocketTransport(WebSocketTransportRegistration registry) {
        registry.setMessageSizeLimit(50 * 1024 * 1024); //this not work todo
        registry.setSendBufferSizeLimit(50 * 1024 * 1024);
        registry.setDecoratorFactories(agentWebSocketHandlerDecoratorFactory());
    }

  @Bean
        public  AgentWebSocketHandlerDecoratorFactory agentWebSocketHandlerDecoratorFactory() {
        return new AgentWebSocketHandlerDecoratorFactory();
    }

the AgentWebSocketHandlerDecoratorFactory will proxy the WebSocketHandler to a custom DelegatingIntroductionInterceptor

import org.springframework.aop.framework.ProxyFactory;
import org.springframework.aop.support.AopUtils;
import org.springframework.aop.support.DefaultIntroductionAdvisor;
import org.springframework.aop.target.SingletonTargetSource;
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.handler.WebSocketHandlerDecoratorFactory;

public class AgentWebSocketHandlerDecoratorFactory implements WebSocketHandlerDecoratorFactory {


    @Override
    public WebSocketHandler decorate(WebSocketHandler handler) {
        ProxyFactory proxyFactory = new ProxyFactory();
        proxyFactory.setTargetClass(AopUtils.getTargetClass(handler));
        proxyFactory.setTargetSource(new SingletonTargetSource(handler));
        proxyFactory.addAdvisor(new DefaultIntroductionAdvisor(new SubProtocolWebSocketHandlerInterceptor()));
        proxyFactory.setOptimize(true);
        proxyFactory.setExposeProxy(true);
        return (WebSocketHandler) proxyFactory.getProxy();

    }

}

and the custom DefaultIntroductionAdvisor will intercept the WebSocketHandler afterConnectionEstablished and set WebSocketSession textMessageSizeLimit

import org.aopalliance.intercept.MethodInvocation;
import org.springframework.aop.support.DelegatingIntroductionInterceptor;
import org.springframework.web.socket.WebSocketSession;

public class SubProtocolWebSocketHandlerInterceptor extends DelegatingIntroductionInterceptor {

    @Override
    protected Object doProceed(MethodInvocation mi) throws Throwable {
        if(mi.getMethod().getName().equals("afterConnectionEstablished") ) {
            WebSocketSession session = (WebSocketSession) mi.getArguments()[0];
            session.setTextMessageSizeLimit(50*1024*1024);
        }
        return super.doProceed(mi);
    }
}

This is tested and will accept message biger the 16KB in the presented case message limit size is 50 * 1024 * 1024

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM