如何使用node-serialport合并ESP32串口发送的JSON分块数据?
解决串口接收大JSON被拆分的问题
嘿,这个场景我太熟了!串口传输大体积数据时,因为硬件缓冲区的限制,肯定会被拆成多个片段发送。你用Readline解析后拿到的单行片段,其实就是拆分后的块,咱们只需要把这些片段拼起来,直到能得到一个完整可解析的JSON就行。给你三个实用的解决方案,按靠谱程度排序:
方案一:给JSON加边界标记(最推荐,需要修改ESP32代码)
如果能控制ESP32的发送逻辑,在每个完整JSON的前后加上唯一的标记(比如[JSON_START]和[JSON_END]),接收端就能精准识别完整的JSON块,完全避免解析错误。
ESP32端发送示例(伪代码)
// 生成你的大JSON字符串 String largeJson = getYourBigJsonObject(); // 发送开头标记+JSON+结尾标记 Serial.print("[JSON_START]"); Serial.print(largeJson); Serial.println("[JSON_END]");
树莓派端接收代码
let jsonBuffer = ''; const START_MARK = '[JSON_START]'; const END_MARK = '[JSON_END]'; function handleData(data) { // 把收到的行片段加到缓冲区 jsonBuffer += data; // 检查是否包含结束标记 const endPos = jsonBuffer.indexOf(END_MARK); if (endPos !== -1) { // 找到开始标记的位置 const startPos = jsonBuffer.indexOf(START_MARK); if (startPos !== -1) { // 提取中间的JSON内容 const rawJson = jsonBuffer.slice(startPos + START_MARK.length, endPos).trim(); try { const completeJson = JSON.parse(rawJson); // 这里处理完整的JSON对象 console.log('收到完整JSON:', completeJson); // 清空缓冲区,注意保留结束标记之后的内容(防止下一个JSON的片段已经过来) jsonBuffer = jsonBuffer.slice(endPos + END_MARK.length); } catch (err) { console.error('JSON解析失败:', err); // 出错就清空缓冲区,避免垃圾数据积累 jsonBuffer = ''; } } else { // 只有结束标记没有开始,说明之前的片段丢失了,直接清空 jsonBuffer = ''; } } }
方案二:缓冲区累加+尝试解析(无需修改ESP32代码)
如果没法改ESP32的代码,就用这个方法:每次收到片段就加到缓冲区,然后尝试用JSON.parse解析,成功就说明拿到了完整的JSON,失败就继续等待下一个片段。
树莓派端代码
// 定义模块级别的缓冲区,用来累加JSON片段 let jsonBuffer = ''; function handleData(data) { // 把新收到的行数据去掉多余空格后加到缓冲区 jsonBuffer += data.trim(); try { // 尝试解析缓冲区内容 const completeJson = JSON.parse(jsonBuffer); // 解析成功!处理完整JSON console.log('完整JSON:', completeJson); // 清空缓冲区,准备接收下一个JSON jsonBuffer = ''; } catch (err) { // 解析失败,说明内容还不完整,继续等待下一个片段 console.debug('片段不完整,继续累加:', jsonBuffer); } }
这个方法的核心是利用JSON.parse的特性:只有完整的JSON才能被成功解析,不完整的片段会抛出错误,我们就靠这个判断是否已经拿到了完整的对象。
方案三:大括号计数法(适合单个对象结构的JSON)
如果你的JSON是单个对象(外层是一对{}),可以通过统计大括号的数量来判断是否完整——当{和}的数量相等时,就说明可能是一个完整的JSON。
树莓派端代码
let jsonBuffer = ''; let braceCounter = 0; function handleData(data) { jsonBuffer += data.trim(); // 遍历字符,统计大括号数量 for (const char of jsonBuffer) { if (char === '{') braceCounter++; else if (char === '}') braceCounter--; } // 当大括号数量回到0,且缓冲区不为空时尝试解析 if (braceCounter === 0 && jsonBuffer.length > 0) { try { const completeJson = JSON.parse(jsonBuffer); console.log('完整JSON:', completeJson); jsonBuffer = ''; braceCounter = 0; } catch (err) { console.error('JSON格式错误:', err); jsonBuffer = ''; braceCounter = 0; } } }
这个方法适合JSON结构固定的场景,比如始终是单个对象,嵌套的大括号也能正确计数。
内容的提问来源于stack exchange,提问作者Woof
相关产品推荐
相关产品推荐

