如何将流式API返回的JSON分块拆分为独立JSON对象?
解决流式API多段JSON解析问题
核心思路
流式API返回的chunk可能拆分在任意位置(比如单个JSON被拆成多个chunk,或一个chunk包含多个完整JSON),因此需要:
- 维护缓冲区累积未处理字符
- 通过括号计数器识别完整JSON对象(兼容嵌套对象场景)
- 解析完整JSON后加入结果集,剩余字符留到下一轮处理
修改后的代码
const getProductData = async (url: string) => { const results: any[] = []; let buffer = ''; // 累积未处理的字符缓冲区 let braceCount = 0; // 跟踪大括号嵌套层级 let startIndex = 0; // 当前待解析JSON的起始位置 try { const response = await fetch(url); if (!response.body) return results; const stream = response.body.pipeThrough(new TextDecoderStream()); const reader = stream.getReader(); while (true) { const { value, done } = await reader.read(); if (done) { // 处理最后剩余的缓冲区内容 if (buffer.trim()) { try { const json = JSON.parse(buffer.trim()); results.push(json); } catch (e) { console.error("解析最后剩余内容失败:", e); } } return results; } if (value) { buffer += value; // 遍历缓冲区寻找完整JSON for (let i = startIndex; i < buffer.length; i++) { const char = buffer[i]; if (char === '{') { braceCount++; } else if (char === '}') { braceCount--; // 大括号层级归0,说明找到完整JSON对象 if (braceCount === 0) { const jsonStr = buffer.slice(startIndex, i + 1).trim(); try { const json = JSON.parse(jsonStr); results.push(json); } catch (e) { console.error("解析JSON失败:", e, "内容:", jsonStr); } // 更新起始位置,跳过已处理内容 startIndex = i + 1; } } } // 清理已处理的缓冲区内容,优化内存 if (startIndex > 0) { buffer = buffer.slice(startIndex); startIndex = 0; braceCount = 0; } } } } catch (e) { console.error("请求或流处理失败:", e); return results; } };
关键细节说明
- 缓冲区管理:避免拆分的JSON片段无法解析,确保所有字符都被累积到完整JSON出现时再处理
- 嵌套兼容:通过计数器跟踪
{和}的数量,即使JSON包含嵌套对象也能准确识别完整边界 - 错误隔离:单个JSON解析失败不影响后续内容处理,方便排查问题
- 内存优化:及时截断已处理的缓冲区内容,防止内存占用过高
简化场景提示
如果确认API返回的JSON没有嵌套对象,也可以用更简单的方式:将所有chunk拼接后按/}\s*{/分割,再给每个片段补全大括号后解析,但嵌套场景下计数器方法更可靠。
内容的提问来源于stack exchange,提问作者BreenDeen
相关产品推荐
相关产品推荐

