STOMP Spring WebSocket 消息超出大小限制
STOMP Spring WebSocket message exceeds size limit
我正在将 Spring WebSocket 实施到我们的 Spring MVC 网络应用程序中。然而,当我试图向端点发送一条非常大的消息时,我 运行 进入了超过大小限制的消息。
我收到以下错误:
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>
我正在研究如何进行部分消息传递,post一旦我发现并让它工作,就会post这里
考虑 <websocket:message-broker>
定义的 <websocket:transport message-size=""/>
选项:
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.
在使用 WebSocketMessageBrokerConfigurer.configureWebSocketTransport(WebSocketTransportRegistration)
实现和 setMessageSizeLimit()
的注解配置中也可以实现同样的效果。
当设置默认值 65kb 时,我遇到了类似 javascript 的错误。然后我将其设置为随机值,再次出现类似
的错误
connection was interrupted
。所以尝试增加时间限制,这对我有用。实际上当超过限制时,消息被发送到 packets/or 帧,并且当它从服务器接收响应时,它超时了。
您可以使用如下调整
@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
评论为 FIX 的行为我解决了问题。
考虑 <websocket:message-broker>
定义的 <websocket:transport message-size=""/>
选项:
配置传入子协议消息的最大大小。例如,当使用 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 消息大小,但 WebSocketSession 不是...是 8KB,此方法将使它加倍。不作为我们要发送的消息。
我不知道如何解决这个问题;您需要设置 WebSocketSession TextMessageSizeLimit
。也许更了解 spring 引导工厂的人知道 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
会拦截WebSocketHandlerafterConnectionEstablished
并设置WebSocketSessiontextMessageSizeLimit
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
我遇到过同样的问题并通过配置 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;
}
}
我正在将 Spring WebSocket 实施到我们的 Spring MVC 网络应用程序中。然而,当我试图向端点发送一条非常大的消息时,我 运行 进入了超过大小限制的消息。
我收到以下错误:
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>
我正在研究如何进行部分消息传递,post一旦我发现并让它工作,就会post这里
考虑 <websocket:message-broker>
定义的 <websocket:transport message-size=""/>
选项:
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.
在使用 WebSocketMessageBrokerConfigurer.configureWebSocketTransport(WebSocketTransportRegistration)
实现和 setMessageSizeLimit()
的注解配置中也可以实现同样的效果。
当设置默认值 65kb 时,我遇到了类似 javascript 的错误。然后我将其设置为随机值,再次出现类似
的错误connection was interrupted
。所以尝试增加时间限制,这对我有用。实际上当超过限制时,消息被发送到 packets/or 帧,并且当它从服务器接收响应时,它超时了。
您可以使用如下调整
@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
评论为 FIX 的行为我解决了问题。
考虑 <websocket:message-broker>
定义的 <websocket:transport message-size=""/>
选项:
配置传入子协议消息的最大大小。例如,当使用 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 消息大小,但 WebSocketSession 不是...是 8KB,此方法将使它加倍。不作为我们要发送的消息。
我不知道如何解决这个问题;您需要设置 WebSocketSession TextMessageSizeLimit
。也许更了解 spring 引导工厂的人知道 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
会拦截WebSocketHandlerafterConnectionEstablished
并设置WebSocketSessiontextMessageSizeLimit
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
我遇到过同样的问题并通过配置 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;
}
}