You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 16:10:08