Javascript is required

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

针对开发者在接口调试中遇到的 Unexpected token、BOM 头部及不可见字符导致的 JSON.parse 崩溃问题的定位与完整修护指南。

作者: Tiny's Tool Core Team更新: 2026-08-04

INTERACTIVE TOOL DIAGNOSTIC WORKBENCH

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

JSON 校验与错误定位器

1. 什么是 JSON 校验与错误定位?

JSON(JavaScript Object Notation)是现代 Web API 与微服务架构中通用的数据交换格式。然而,JSON RFC 8259 规范极其严格,哪怕数据中存在一个多余的逗号、单引号,或者隐藏的 Unicode 不可见字符,都会导致原生 JSON.parse() 发生运行时崩溃。

在对接老旧后台接口、第三方 Webhook 回调或处理由 Windows 记事本编辑的文件时,开发者经常遇到模糊的语法报错(例如 Unexpected token),却无法定位具体的行号与列号。

2. 常见语法报错现象与复现

1. 不可见 UTF-8 BOM 头部标识 (\uFEFF)

Windows 记事本等编辑器在保存 UTF-8 文件时常在头部添加 BOM 标记。当直接传给 JSON.parse() 时,解析器在第 0 个位置就会崩溃:

text
SyntaxError: Unexpected token '' (0xFEFF) in JSON at position 0
js
// 复现代码:第 0 位包含隐藏 BOM
const bomPayload = "\uFEFF{\"status\": 200, \"message\": \"OK\"}";
JSON.parse(bomPayload); // 抛出异常!

2. 零宽隐藏字符 (\u200B, \u200C)

从飞书、钉钉、PDF 文档或网页文档复制 JSON 时,文本中常夹带隐藏的零宽空格(Zero-Width Space),这会导致 JSON 键名或语法解析失败:

js
// 复现代码:Key 名称内部混入零宽字符
const invisiblePayload = '{"username\u200B": "admin"}';
const parsed = JSON.parse(invisiblePayload);
console.log(parsed.username); // undefined!(实际 Key 为 "username​")

3. 对象或数组末尾的多余逗号 (Trailing Comma)

虽然 ECMAScript 2017 允许对象字面量保留尾随逗号,但标准 JSON 语法严格禁止:

js
// 复现代码:末尾多余逗号
const trailingCommaPayload = '{"id": 101, "role": "developer",}';
JSON.parse(trailingCommaPayload); // SyntaxError: Unexpected token }

4. 单引号与未转义换行符

标准 JSON 严格要求键名与字符串值使用双引号 (") 包裹。使用单引号 (') 或在字符串中混入未转义的直接换行符均会导致语法失效。

3. 根因深度分析

  • RFC 8259 严苛规范:原生 JSON.parse() 基于严格的词法分析,不支持容错容灾。
  • 编辑器遗留机制:Windows 默认记事本保存 UTF-8 时会注入 3 字节 BOM 头 (EF BB BF)。
  • 富文本复制污染:聊天软件与网页在拷贝代码块时会将不可见空格带入剪贴板。

4. 逐步清洗算法与可运行代码

您可以在前端项目中使用如下 TypeScript 函数对 JSON 字符串进行前置清洗与诊断:

ts
export interface JsonDiagnosticResult {
    isValid: boolean;
    cleanText: string;
    hasBom: boolean;
    zeroWidthCount: number;
    trailingCommaFixed: boolean;
}

export function sanitizeAndValidateJson(input: string): JsonDiagnosticResult {
    let text = input;
    let hasBom = false;
    let zeroWidthCount = 0;
    let trailingCommaFixed = false;

    // 1. 清除 UTF-8 BOM 头 ()
    if (text.charCodeAt(0) === 0xFEFF) {
        text = text.slice(1);
        hasBom = true;
    }

    // 2. 匹配并剔除零宽隐藏字符
    const zeroWidthRegex = /[​-‍‎‏‪-‮]/g;
    const matches = text.match(zeroWidthRegex);
    if (matches) {
        zeroWidthCount = matches.length;
        text = text.replace(zeroWidthRegex, "");
    }

    // 3. 自动修复末尾多余逗号
    const trailingCommaRegex = /,s*([}]])/g;
    if (trailingCommaRegex.test(text)) {
        trailingCommaFixed = true;
        text = text.replace(trailingCommaRegex, "$1");
    }

    // 4. 执行标准解析校验
    let isValid = false;
    try {
        JSON.parse(text);
        isValid = true;
    } catch {
        isValid = false;
    }

    return { isValid, cleanText: text, hasBom, zeroWidthCount, trailingCommaFixed };
}

5. 常见问题解答 (FAQ)

Q1: 为什么使用 Windows 记事本编辑 JSON 后接口会报错?

Windows 记事本在将文件保存为 UTF-8 时,会默认在文件头部写入 3 字节的 Byte Order Mark (BOM: 0xEF, 0xBB, 0xBF)。当后端 Node.js/V8 执行 JSON.parse() 时,无法识别首位的 0xFEFF 字符,从而抛出 SyntaxError: Unexpected token

Q2: 批量处理包含多余逗号的 JSON 文本最快的方法是什么?

可以使用正则表达式 cleanJson = input.replace(/,\s*([\}\]])/g, "$1") 进行替换,也可以使用本站提供的 JSON 校验与错误定位器 网页工具,实现一键定位与一键自动修复。

Q3: 在本工具粘贴生产环境的敏感 JSON 日志是否安全?

解析在浏览器本地内存中完成,工具本身不会主动上传粘贴内容。但生产数据仍应先遵守组织安全策略、尽量缩减样本并移除密钥;使用前也应核对实际部署页面所加载的脚本。