PHP中如何读取NDJSON流响应?Guzzle调用后解析遇难题
解决Guzzle请求NDJSON后的解析问题
核心问题分析
你遇到的问题本质是返回的内容不符合标准NDJSON规范:标准NDJSON要求每个JSON对象必须是单行结构,换行仅作为不同对象的分隔符。如果单个JSON对象内部包含换行(格式化后的多行JSON),会直接破坏对象边界识别逻辑,导致解析库失败。
解决方案步骤
1. 先验证响应格式合法性
先排查响应内容是否符合NDJSON标准,用以下代码逐行测试单个JSON的有效性:
$body = $response->getBody(); while (!$body->eof()) { $line = rtrim($body->readLine(), "\r\n"); // 打印单行内容和解析结果,判断是否为有效单行JSON var_dump($line, json_decode($line)); }
如果某一行json_decode返回null,说明该行是带内部换行的格式化JSON,属于非标准格式。
2. 修复非标准NDJSON的解析方法
如果API确实返回非标准格式,可通过以下两种方式处理:
方法一:按JSON语法边界合并完整对象
利用JSON的{}配对特征识别单个对象的完整边界,忽略内部换行:
$body = $response->getBody(); $buffer = ''; $depth = 0; while (!$body->eof()) { $char = $body->read(1); if ($char === '{') { $depth++; } elseif ($char === '}') { $depth--; // 当层级回到0,说明一个完整JSON对象结束 if ($depth === 0) { $buffer .= $char; $data = json_decode($buffer); // 这里处理解析后的$data $buffer = ''; continue; } } // 跳过换行符,保留其他字符 if (!in_array($char, ["\n", "\r"])) { $buffer .= $char; } }
方法二:清理内部换行后按标准NDJSON解析
如果确定JSON字符串值中没有换行(避免破坏字符串内容),可先清理所有内部换行,再按行分割:
$content = $response->getBody()->getContents(); // 替换JSON内部的空白换行(仅适用于字符串无换行的场景) $cleanContent = preg_replace('/\s+(?=(?:[^"]*"[^"]*")*[^"]*$)/', ' ', $content); $lines = explode("\n", $cleanContent); foreach ($lines as $line) { $line = trim($line); if (empty($line)) continue; $data = json_decode($line); // 处理解析后的$data }
3. 适配sunaoka/ndjson库使用
如果坚持用该库,可先将处理后的标准NDJSON写入临时文件,再读取:
$tempFile = tmpfile(); $body = $response->getBody(); $buffer = ''; $depth = 0; while (!$body->eof()) { $char = $body->read(1); if ($char === '{') { $depth++; } elseif ($char === '}') { $depth--; if ($depth === 0) { $buffer .= $char . "\n"; // 添加标准NDJSON换行分隔符 fwrite($tempFile, $buffer); $buffer = ''; continue; } } if (!in_array($char, ["\n", "\r"])) { $buffer .= $char; } } // 重置文件指针到开头 fseek($tempFile, 0); // 使用sunaoka/ndjson读取解析 $reader = new \Sunaoka\Ndjson\Reader($tempFile); foreach ($reader as $data) { // 处理解析后的$data } fclose($tempFile);
4. 根本解决:要求API返回标准格式
以上方法均为临时适配方案,最稳妥的方式是联系API开发者,让他们返回符合规范的NDJSON——每个JSON对象单独一行,仅用换行分隔不同对象。
内容的提问来源于stack exchange,提问作者Florian B
相关产品推荐
相关产品推荐

