STOMP Spring WebSocket消息超出大小限制。

9

我正在将Spring WebSocket集成到我们的Spring MVC Web应用程序中。然而,当我尝试向端点发送非常大的消息时,我遇到了消息超出大小限制的问题。

我收到了以下错误:

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]

以下是我的配置信息:

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

return stringRet;
}

XML配置如下所示:
<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>

客户端代码如下所示:
function versionFiles() {
        stompClient.send("/testbrkr/user/sockettest", {}, JSON.stringify(listIds));
    }

您能告诉我一个好的解决方法吗?

答案: 如果您知道最大大小限制,可以尝试以下解决方法:

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

我正在寻找如何进行部分消息传递,一旦我找到并使其正常工作,我会在这里发布。

5个回答

7
当默认值设置为65kb时,我遇到了类似的javascript错误...然后我将其设置为一些随机值,又遇到了一些错误,如连接中断。于是我尝试增加时间限制,这对我有用。实际上,当限制超过时,消息会被发送到数据包/帧中,在它接收服务器响应时,它会超时。您可以按如下方式进行调整。
@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

        }
---
}

1
除了@Ashutosh的回答,我还发现了这个Spring文档页面,你可以参考一下: https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/socket/config/annotation/WebSocketTransportRegistration.html - Minjeong Choi

6
考虑使用 <websocket:transport message-size=""/> 选项来定义 <websocket:message-broker>

配置传入子协议消息的最大大小。 例如,当使用 SockJS 回退选项时,STOMP 消息可能会被接收为多个 WebSocket 消息或多个 HTTP POST 请求。

在注释配置中,可以使用 WebSocketMessageBrokerConfigurer.configureWebSocketTransport(WebSocketTransportRegistration) 实现并使用 setMessageSizeLimit() 来实现相同的效果。

谢谢,这部分解决了发送消息的问题,但是我无法在客户端接收到消息... - Nikhil Das Nomula
也许 setSendBufferSizeLimit() 对你来说是适合的选择? - Artem Bilan
成功了!以下是我在xml中的实现方式:<websocket:transport message-size="75536" send-buffer-size="75536"> </websocket:transport> 我目前正在研究部分消息的处理方法。 - Nikhil Das Nomula
Spring框架中是否有现成的支持来分割WebSocket消息的功能? - Gazeciarz
看起来完全是另一个问题。 是的:Spring集成为您提供了解决方案:http://docs.spring.io/spring-integration/reference/html/messaging-routing-chapter.html#splitter - Artem Bilan
这里是一个实际文档:https://docs.spring.io/spring-integration/reference/html/message-routing.html#splitter - Artem Bilan

1

我曾经遇到过相同的问题,通过配置WebSocketTransportRegistration和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;
    }
}

1
        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


注释为FIX的行解决了我的问题。



0
考虑在定义中使用选项:
配置传入子协议消息的最大大小。例如,当使用SockJS回退选项时,STOMP消息可能会作为多个WebSocket消息或多个HTTP POST请求接收。
在注释配置中也可以实现相同的功能。
WebSocketMessageBrokerConfigurer.configureWebSocketTransport(WebSocketTransportRegistration) 

涉及实现问题,可以使用 setMessageSizeLimit() 方法解决。

这是正确的方法,但是... 如果你正在使用 Spring WebSocket,则需要考虑 STOMP 消息。

StompSubProtocolHandler

并且

@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()));
    }

所以这里是Spring的一个bug,消息大小被设置为websocket:transport message-size,但WebSocketSession没有...是8KB,而这个方法会将其加倍。不是我们想要发送的消息。

我不知道如何修复它;您需要设置WebSocketSession TextMessageSizeLimit。也许有人更了解Spring Boot Factory,知道如何以Spring的方式更改WebSocketSession textMessageSizeLimit。 无论如何,我用Aop DelegatingIntroductionInterceptor解决了它。

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();
    }

AgentWebSocketHandlerDecoratorFactory 将代理 WebSocketHandler 到一个自定义的 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();

    }

}

并且自定义的 DefaultIntroductionAdvisor 将拦截 WebSocketHandler 的 afterConnectionEstablished 并设置 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);
    }
}

这经过测试,可以接受大于16KB的消息,在本例中,消息限制大小为50 * 1024 * 1024


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接