gjson不支持流式解析,仅接受完整[]byte或string;处理gb级json必须用json.decoder配合token()手动控制token流,逐个解码对象并用dec.more()判断数组边界。

别用 gjson 做流式解析——它不支持流,只接受完整 []byte 或 string,所谓“超大 JSON 流式解析”是伪命题。真要处理 GB 级 JSON,必须用标准库 json.Decoder 配合手动 token 控制;gjson 只适合从已读入内存的响应体里快速取几个字段。
gjson.GetBytes() 本质是全量加载,不是流式
gjson.GetBytes 内部会把整个输入 []byte 当作不可变快照,按字节线性扫描路径,不做任何缓冲跳过或状态维护。这意味着:
- 你必须先调
io.ReadAll(r.Body)把整个 HTTP body 或文件读进内存,再传给gjson.GetBytes—— 这一步已经 OOM 了 - 即使只取
"user.id",它仍要从头扫到匹配位置,对 500MB JSON,扫描本身就要几百毫秒,且无法中断 - 没有
io.Reader接口支持,不能接bufio.Reader、gzip.Reader或网络连接,更不支持边收边查
真正流式解析只能靠 json.Decoder.Token()
当 JSON 是一个巨型数组(如日志导出 [{...},{...},...]),你要逐条处理而不爆内存,唯一可靠路径是手动控制 token 流:
用于端到端视频本地化流程的轻量编排器,路由至四个专注子技能——/wjs-transcribing-audio、/wjs-translating-subtitles...
- 先
dec.Token()检查是否为'[',否则 panic 或跳过非法前导 - 进入
for dec.More() { ... }循环,每次dec.Decode(&item)解一个对象 - 循环内若发现字段缺失或类型错乱,用
json.RawMessage接住原始字节,避免map[string]interface{}的反射开销和内存膨胀 - 务必在
dec.Decode()后检查err == io.EOF,但不要依赖它退出循环——dec.More()才是数组边界权威判断
gjson 的合理使用场景和致命限制
它快,但快得有前提:输入必须小、路径固定、无需校验、不关心结构完整性。
- 适用:HTTP 中间件中提取
"trace_id"或"user_id",且已通过ContentLength限流(如 ≤2MB) - 禁用:解析上游返回的 chunked 编码响应、带 BOM 的 JSON、gzip 压缩未解压的 body——
gjson会直接 panic - 陷阱:
result.String()对不存在字段返回空字符串,result.Exists()才是安全判断;路径拼接(如"data." + key)可能被注入..或数组越界 - 替代方案:若真需“一行取值 + 类型安全”,用
jsoniter.ConfigCompatibleWithStandardLibrary+jsoniter.Get,它支持io.Reader封装,但性能略低于gjson
真正的性能极致不在解析器选型,而在数据契约设计:上游能否按行分隔 JSON 对象(NDJSON)?能否提供 schema 提前过滤字段?gjson 再快,也救不了没做流量控制、没设 body 上限、没预检格式的烂接口。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










