Javascript is required

如何排查 JSON 语法错误:行列定位、BOM 头、零宽隐形字符与尾随逗号诊治指南

系统排查 JSON.parse 的 Unexpected token 等语法错误,定位 UTF-8 BOM、零宽字符、尾随逗号、单引号及未转义控制字符,并提供安全清理、行列定位、严格校验与修复验证步骤,帮助诊断 API 响应和复制文本中的无效 JSON。

作者: Tiny's Tool Core Team•更新: 2026-09-14

INTERACTIVE TOOL DIAGNOSTIC WORKBENCH

在浏览器本地尝试对应的调试工具

JSON 校验与错误定位器→

先检查原始输入

对实际收到的 API 响应执行 JSON.parse,再考虑修复。先确认 HTTP 状态和 Content-Type:HTML 错误页不是 JSON。不同 JavaScript 引擎的报错文本与位置格式可能不同。

区分 BOM、零宽字符与合法数据

部分编辑器支持保存为带 BOM 的 UTF-8。解码后的字符串若以 U+FEFF 开头,JSON.parse 会报错;仅在输入约定允许时移除开头的这个标记。不要假设所有编辑器都会添加 BOM。

JSON 字符串外的零宽字符不是合法 JSON 空白;引号内的键名或值却可以合法包含这些字符。例如 U+200D 用于连接 Emoji。应定位并提示人工确认,不能全局删除,否则可能改变原始数据。

尾随逗号与字符串内容

闭合括号前的逗号可能是语法错误,但引号内部的逗号与括号必须保留。单引号、注释和未转义控制字符需要分别诊断,不能用全局替换统一处理。

使用识别字符串边界的保守修复

下面的独立 TypeScript 函数跟踪字符串与转义引号,只尝试移除开头的 BOM 和字符串外的尾随逗号。完整候选文本通过 JSON.parse 后才返回修复建议。应用结果前仍需核对差异。

ts

/** Conservative repair: preserve string contents; never strip invisible characters globally. */
export function repairJsonSyntax(input: string): { candidate?: string; trailingCommaFound: boolean } {
    const text = input.charCodeAt(0) === 0xfeff ? input.slice(1) : input;
    let output = "";
    let inString = false;
    let escaped = false;
    let previous = "";
    let trailingCommaFound = false;
    for (let index = 0; index < text.length; index++) {
        const char = text[index];
        if (inString) {
            output += char;
            if (escaped) escaped = false;
            else if (char === "\\") escaped = true;
            else if (char === '"') { inString = false; previous = '"'; }
            continue;
        }
        if (char === '"') inString = true;
        if (char === ",") {
            let next = index + 1;
            while (next < text.length && /[\x20\t\r\n]/.test(text[next])) next++;
            const closes = text[next] === "]" || text[next] === "}";
            if (closes && previous && !"[{,:".includes(previous)) {
                trailingCommaFound = true;
                continue;
            }
        }
        output += char;
        if (!/[\x20\t\r\n]/.test(char)) previous = char;
    }
    // Only offer a repair if the complete candidate is valid JSON.
    try {
        JSON.parse(output);
        return { candidate: output === input ? undefined : output, trailingCommaFound };
    } catch {
        return { trailingCommaFound };
    }
}

验证合法数据没有被修改

测试字符串中的逗号、转义引号、反斜杠、嵌套数组和 Emoji。合法 JSON 应逐字保持不变;[, ]、{,} 等错误不能被改成空容器;数字中夹入不可见字符时必须继续报错。

ts

const original = JSON.stringify({ text: ",}", emoji: "👩‍💻" });

console.assert(repairJsonSyntax(original).candidate === undefined);

console.assert(repairJsonSyntax("[,]").candidate === undefined);

console.assert(repairJsonSyntax('{"items":[1,2,],}').candidate === '{"items":[1,2]}');

定位剩余错误并复核

使用 /tools/json/json-validator 查看原始错误以及引擎提供的行列信息。无法获取位置时,不应猜测错误位于首字符。修复后还要按接口约定检查键名和值。

HTML 响应、重复解析与数据截断的排查见 /articles/json-unexpected-token;Unicode 转义与代理对见 /articles/unicode-json-escapes。

数据处理与能力边界

工具在浏览器本地解析,不主动上传粘贴内容。生产样本仍应最小化并先移除密钥。JSON.parse 成功仅证明语法有效,不证明数据满足 Schema、键名没有重复或大整数没有精度损失。

参考规范

RFC 8259:JSON 语法、字符串与 UTF-8