rsocket-js与Spring-rsocket传输超65536字节数据时解码异常
问题场景
使用rsocket-websocket-client(浏览器端)与Spring Boot构建的RSocket服务端通信,当客户端通过requestResponse返回包含100万元素数组的JSON数据时,Firefox可正常运行,但Chrome和Edge会触发服务端JSON反序列化错误,提示输入不完整。
客户端代码(浏览器)
async function initRequest() { const transportOpts = { url: 'ws://127.0.0.1:6565', debug: true } const setup = { dataMimeType: APPLICATION_JSON.string, keepAlive: 10000, lifetime: 90000, metadataMimeType: MESSAGE_RSOCKET_ROUTING.string, } const responder = { requestResponse: function (request) { console.log('get req from server'); return new Single((subscriber) => { subscriber.onSubscribe(() => {}); // 返回大体积数据 subscriber.onComplete({ data: { "data": new Array(1000000).fill(0), } }) }) } } const serializers = { data: JsonSerializer, metadata: IdentitySerializer, } const errorHandler = (e) => { console.log(e); } const transport = new RSocketWebSocketClient(transportOpts); const client = new RSocketClient({setup, transport, responder, serializers, errorHandler}); rSocket = await client.connect(); console.log('init client'); rSocket.requestResponse({ data: '3434', metadata: String.fromCharCode('hello'.length) + 'hello' }).subscribe({ onComplete: (response) => { console.log(response); }, onError: (error) => { console.log(error); } }) return rSocket; }
服务端代码(Spring Boot)
private RSocketRequester requester; @ConnectMapping public void handleMessage(RSocketRequester requester) { System.out.println("connected"); this.requester = requester; requester.rsocketClient().source().doOnError(Throwable::printStackTrace).subscribe(r -> r.onClose().doFinally(v -> { System.out.println("closed"); this.requester = null; }).subscribe()); } @Scheduled(fixedRate = 5000) public void schedule() { if (requester == null) { return; } // 向客户端发送requestResponse请求 requester.route("ddd").data("{}").retrieveMono(HashMap.class).doOnNext(System.out::println).subscribe(); }
服务端错误日志
2025-04-13T00:07:56.235+08:00 ERROR 19972 --- [demo] [tor-http-nio-12] reactor.core.publisher.Operators : Operator called default onErrorDropped
reactor.core.Exceptions$ErrorCallbackNotImplemented: org.springframework.core.codec.DecodingException: JSON decoding error: Unexpected end-of-input within/between Array entries
Caused by: org.springframework.core.codec.DecodingException: JSON decoding error: Unexpected end-of-input within/between Array entries
at org.springframework.http.codec.json.AbstractJackson2Decoder.processException(AbstractJackson2Decoder.java:282) ~[spring-web-6.2.5.jar:6.2.5]
at org.springframework.http.codec.json.AbstractJackson2Decoder.decode(AbstractJackson2Decoder.java:218) ~[spring-web-6.2.5.jar:6.2.5]
at org.springframework.messaging.rsocket.DefaultRSocketRequester$DefaultRequestSpec.lambda$retrieveMono$8(DefaultRSocketRequester.java:299) ~[spring-messaging-6.2.5.jar:6.2.5]
...(后续堆栈信息省略)
解决方案
1. 配置客户端WebSocket帧大小限制
修改客户端传输配置,设置合理的maxFrameSize,让RSocket自动拆分大帧:
const transportOpts = { url: 'ws://127.0.0.1:6565', debug: true, maxFrameSize: 1024 * 1024 // 设置为1MB,根据实际数据调整 }
2. 升级RSocket-JS版本
旧版本的rsocket-websocket-client存在WebSocket分片处理的bug,升级到最新稳定版可修复该问题。
3. 调整服务端RSocket最大帧大小
在Spring Boot配置文件(如application.yml)中增加以下配置,允许服务端接收更大的帧:
spring: rsocket: server: max-frame-size: 16MB # 根据实际数据体积调整
4. 优化数据传输方式
若业务允许,避免一次性返回超大体积数据:
- 使用
RequestStream流式传输替代RequestResponse,分批次返回数据 - 对数据进行压缩后再传输
内容的提问来源于stack exchange,提问作者linkser lin

