You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

WebSocket ws.onmessage合并消息解析错误致断连问题求助

WebSocket合并JSON消息的前端解析解决方案

问题背景

原WebSocket消息处理逻辑如下:

ws.onmessage = function (event) {
        let message = event.data;
        let data = JSON.parse(message);
        parseWSData(data);
}

当服务器短时间内发送多条消息时,前端会收到合并后的消息(如'{"aa":11,"bb":22}{"cc":33,"bb":22}'),直接调用JSON.parse会抛出错误,最终导致WebSocket以错误码1006断开连接。即便用try-catch捕获错误,连接仍会断开。

尝试通过拆分"}{"处理合并消息,但该方案存在缺陷:当JSON字符串中包含"}{"子串时会错误拆分,且运行一段时间后仍会出现解析}或空字符串的错误。最终通过将后端改为异步发送解决了问题,但仍需前端层面的可靠处理方案。

前端可靠处理方案

方案1:使用消息分隔符(推荐)

和后端约定,每条JSON消息末尾添加一个不会出现在JSON内容中的分隔符(比如换行符\n,或自定义标记如|||),后端发送每条消息时都追加该分隔符。前端维护一个缓冲区,每次收到消息后追加到缓冲区,再按分隔符拆分出完整消息解析:

// 全局缓冲区存储未处理的消息片段
let wsBuffer = '';

ws.onmessage = function (event) {
    wsBuffer += event.data;
    // 以换行符作为分隔符示例,可根据约定修改
    const delimiter = '\n';
    let messageList = wsBuffer.split(delimiter);
    // 最后一个元素可能是不完整的消息,放回缓冲区
    wsBuffer = messageList.pop();

    for (const msg of messageList) {
        if (!msg.trim()) continue; // 跳过空消息
        try {
            const data = JSON.parse(msg);
            parseWSData(data);
        } catch (e) {
            console.error('JSON解析失败:', e, '消息内容:', msg);
            // 可根据业务需求选择记录错误后继续,或触发重连逻辑
        }
    }
};

这种方式通过明确的分隔符区分消息,完全避免了JSON内容干扰拆分逻辑,是最稳定可靠的方案。

方案2:渐进式JSON解析(无需后端配合)

如果无法修改后端,可采用渐进式解析逻辑:维护缓冲区,从开头尝试解析完整JSON,解析成功则处理并截断缓冲区,失败则尝试定位最后一个可能的闭合位置,逐步处理:

let wsBuffer = '';

ws.onmessage = function (event) {
    wsBuffer += event.data;
    while (true) {
        let parsedData = null;
        let validEndIndex = 0;

        // 尝试解析整个缓冲区
        try {
            parsedData = JSON.parse(wsBuffer);
            validEndIndex = wsBuffer.length;
        } catch (e) {
            // 解析失败,尝试定位最后一个闭合大括号
            const lastCloseBrace = wsBuffer.lastIndexOf('}');
            if (lastCloseBrace === -1) break; // 无完整JSON结构,退出循环

            // 尝试解析到最后一个闭合大括号的位置
            try {
                parsedData = JSON.parse(wsBuffer.slice(0, lastCloseBrace + 1));
                validEndIndex = lastCloseBrace + 1;
            } catch (e2) {
                // 到该位置仍无法解析,丢弃错误片段
                wsBuffer = wsBuffer.slice(lastCloseBrace + 1);
                continue;
            }
        }

        if (parsedData) {
            parseWSData(parsedData);
            wsBuffer = wsBuffer.slice(validEndIndex);
        } else {
            break;
        }
    }
};

该方案无需后端修改,但逻辑较复杂,极端场景下(如嵌套多层JSON)可使用成熟的流式JSON解析库(如oboe.js)简化开发。

原有方案的问题分析

之前使用split("}{")的方案存在核心缺陷:

  • 若JSON字符串中包含"}{"(比如{"desc":"示例}{文本"}),会错误拆分消息,导致后续解析失败。
  • 无法处理半完整消息(如收到'{"aa":11,"bb":22}{"cc":'),拆分后最后一段无法解析,且错误内容会残留到后续处理中。

内容的提问来源于stack exchange,提问作者GainLos

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 17:32:54