json.Decoder卡住是因为它等待完整JSON值,不自动处理流式分块或未闭合结构;需确保输入语义清晰(如NDJSON)或明确边界。

json.Decoder 为什么卡在 Decode() 不返回?
因为 json.Decoder 默认等待一个**完整、合法的 JSON 值**——不是“读到多少字节就解析多少”,而是必须看到匹配的 {/[ 和对应的 }/],中间不能截断。常见卡住场景包括:
- HTTP 响应 Body 是 chunked 编码,但服务端还没发完最后一个块(比如数组少了个
]) - 输入是 NDJSON(每行一个 JSON),但你没做换行隔离,直接把整段带换行的字节喂给
Decode() - TCP 连接未关闭,且最后一行 JSON 后没有换行或 EOF
别加 context.WithTimeout 强行中断——这掩盖了流语义不清晰的问题。真正要做的,是让输入有明确边界:用 NDJSON 就按行切;用数组流就手动处理容器 token。
NDJSON 流怎么安全逐行解析?
别用 bytes.Split(data, []byte{'\n'}) 先全加载再切分——JSON 字符串里允许换行,"msg": "line1\nline2" 会被错误拆开。正确方式是组合 bufio.Scanner 和独立 json.Decoder:
- 用
scanner := bufio.NewScanner(r)+scanner.Split(bufio.ScanLines)拆行 - 对每一行
line,创建新解码器:json.NewDecoder(strings.NewReader(line)) - 调
Decode(&v)解析单行,失败只影响当前行,不影响后续
重复创建 Decoder 开销极小,比复用一个实例并手动跳过换行符更可靠——Decoder 不会自动忽略行尾,自己维护状态容易错位。
立即学习“go语言免费学习笔记(深入)”;
顶层是大 JSON 数组时怎么避免 OOM?
文件内容是 [{"id":1},{"id":2},...],直接循环 dec.Decode(&item) 会试图把整个数组当一个值加载,OOM 风险极高。必须用 Token() 或 More() 手动控制解析节奏:
- 先调一次
dec.Token()确认开头是[ - 然后进入
for dec.More() { ... }循环,每次调dec.Decode(&item)解一个元素 -
dec.More()内部会自动吃掉逗号,并在遇到]时返回false
注意:dec.More() 只在已进入数组/对象后有效;如果数组嵌套很深,或字段结构不一致(比如混合 {"type":"user"} 和 {"type":"event"}),建议先用 map[string]interface{} 接收,再根据 type 字段分支处理。
json.Encoder 写完没反应?漏了 Flush()
json.Encoder 内部有缓冲,Encode() 调用后数据可能还卡在编码器 buffer 里,根本没写到底层 io.Writer。尤其在 HTTP 流、WebSocket、stdout 场景下,前端永远收不到第一条消息。
- 每次
enc.Encode(v)后,必须紧跟enc.Flush() - 如果底层 writer 是
bufio.Writer(比如包装了http.ResponseWriter),enc.Flush()只刷它自己的 buffer,你还得再调一次bw.Flush() - 并发写入时,
Encoder不是 goroutine 安全的——每个 goroutine 必须持有自己的Encoder实例
最易被忽略的是:Flush 不是“优化项”,而是流式输出的**必要同步点**;没它,流就卡在服务端 buffer 里,连超时都等不到——因为写操作根本没真正发生。



















