项目场景:
使用springboot自带的websocket库作为客户端向设备进行连接获取设备推送的数据,包括纯数据以及携带base64图片的数据
问题描述
WebSocket接收数据时连接断开,报错1009 The decoded text message was too big for the output buffer and the endpoint does not support partial messages
@Override
protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
// 处理接收到的消息
logger.info("Received message from device: " + message.getPayload());
}
原因分析:
WebSocket缓冲区过小,装不下数据
需要给websocket缓冲区扩容,但是问题就在于全网查询后,包括StackOverflow及ChatGPT的回答都聚焦于两个点
一个是修改tomocat的缓冲区,在jar包启动时加上如下启动命令
-Dorg.apache.tomcat.websocket.DEFAULT_BUFFER_SIZE=327680
一个是写Config类
@Configuration
public class WebSocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
@Bean
public ServletServerContainerFactoryBean createWebSocketContainer() {
ServletServerContainerFactoryBean container = new ServletServerContainerFactoryBean();
// 在此处设置bufferSize
container.setMaxTextMessageBufferSize(512000);
container.setMaxBinaryMessageBufferSize(512000);
container.setMaxSessionIdleTimeout(15 * 60000L);
return container;
}
}
问题也就在这里,这个配置文件并不能解决实际的缓冲区大小,但确实是对的思路。
解决方案:
首先我们查看连接所使用的类的源码
正常通过StandardWebSocketClient client = new StandardWebSocketClient();进行创建一个连接的client,使用默认的配置。但是StandardWebSocketClient是可以构造一个container传入的
public StandardWebSocketClient(WebSocketContainer webSocketContainer) {
Assert.notNull(webSocketContainer, "WebSocketContainer must not be null");
this.webSocketContainer = webSocketContainer;
}
继续查看WebSocketContainer 的源码
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package javax.websocket;
import java.io.IOException;
import java.net.URI;
import java.util.Set;
public interface WebSocketContainer {
long getDefaultAsyncSendTimeout();
void setAsyncSendTimeout(long var1);
Session connectToServer(Object var1, URI var2) throws DeploymentException, IOException;
Session connectToServer(Class<?> var1, URI var2) throws DeploymentException, IOException;
Session connectToServer(Endpoint var1, ClientEndpointConfig var2, URI var3) throws DeploymentException, IOException;
Session connectToServer(Class<? extends Endpoint> var1, ClientEndpointConfig var2, URI var3) throws DeploymentException, IOException;
long getDefaultMaxSessionIdleTimeout();
void setDefaultMaxSessionIdleTimeout(long var1);
int getDefaultMaxBinaryMessageBufferSize();
void setDefaultMaxBinaryMessageBufferSize(int var1);
int getDefaultMaxTextMessageBufferSize();
void setDefaultMaxTextMessageBufferSize(int var1);
Set<Extension> getInstalledExtensions();
}
问题的关键就在这里!set方法告诉我们WebSocketContainer 是可以设置缓冲区大小的
因此解决方案就出来了,在新建客户端连接的时候,构造好container传入就可以自定义缓冲区大小和过期时间了,代码如下
WebSocketContainer container = new WsWebSocketContainer();
// 设置二进制消息缓冲区大小(以字节为单位)
container.setDefaultMaxBinaryMessageBufferSize(5120000);
// 设置文本消息缓冲区大小(以字节为单位)
container.setDefaultMaxTextMessageBufferSize(5120000);
// 设置会话空闲超时时间(以毫秒为单位)
container.setDefaultMaxSessionIdleTimeout(15 * 60000L);
StandardWebSocketClient client = new StandardWebSocketClient(container);
大功告成!