JSONDecodeError 是 json.loads() 或 json.load() 解析非法 JSON 字符串时抛出的异常,因输入不符合 JSON 语法规范,常见原因包括 BOM、单引号、尾逗号、HTML 响应体、未转义字符等。

JSONDecodeError 是什么,为什么它总在读文件或调用 API 后冒出来
JSONDecodeError 是 json.loads() 或 json.load() 解析非法 JSON 字符串时抛出的异常,本质是 Python 发现输入不符合 JSON 语法规范。常见诱因不是“数据没传过来”,而是:字符串开头有 BOM、末尾多逗号、用了单引号、包含 Python 风格的注释、或响应体其实是 HTML 错误页(比如 502/404 返回了 Nginx 默认页面)。
- 网络请求后直接
json.loads(r.text)却没检查r.status_code,结果把 HTML 当 JSON 解了 - 用
open("data.json")读文件时没指定encoding="utf-8-sig",BOM 导致开头出现\ufeff{ - 前端传来的数据字段值里混入了换行符或未转义双引号,后端没做清洗就拼进 JSON 字符串
捕获并定位错误位置的最简方法
别只写 except json.JSONDecodeError: 然后 print("解析失败")——这等于放弃诊断权。Python 的 JSONDecodeError 实例自带 msg、lineno、colno 和 pos 属性,能精确定位到字符级:
try:
data = json.loads(text)
except json.JSONDecodeError as e:
print(f"解析失败:{e.msg}(第{e.lineno}行,第{e.colno}列)")
# 可选:打印出错位置附近 50 个字符
start = max(0, e.pos - 25)
end = min(len(text), e.pos + 25)
print(f"上下文:{text[start:end]!r}")
注意:如果原始文本是二进制(比如从 requests.Response.content 拿的),必须先用 .decode("utf-8") 转成字符串再解析;否则 json.load() 会报 TypeError,不是 JSONDecodeError。
绕过格式问题的临时方案:用 ast.literal_eval() 替代(仅限可信来源)
当确认输入是“类 Python 字典字面量”(比如用单引号、带注释、末尾逗号),且你完全信任数据来源(如本地配置文件、测试 fixture),可用 ast.literal_eval() 作为逃生通道:
立即学习“Python免费学习笔记(深入)”;
python-docx Skill功能概述python-docx Skill是一项面向实际任务的技能,主要用于本Skill提供使用python-docx生成专业Word文档的标准方法和最佳实践;生成安全服务方案文档;核心要点生成技术架构设计文档;生成任何需要专业排版的Word文档;核心库 : python-docx;使用与执行辅助库 : docx.shared , docx.enum , docx.oxml.ns;标准代码模板;1. 文档初始化;2. 字体设置(必须!它将相关步骤、工具调用和结果整理方式集
- 它支持单引号、省略引号的键名(
{key: "val"})、尾随逗号、甚至注释(只要语法合法) - 但绝对不能用于解析不可信输入(如用户提交、第三方 API),因为
ast.literal_eval()仍可能触发某些边界行为,且语义和 JSON 不等价(例如Truevstrue) - 示例:
ast.literal_eval("{'name': 'Alice', 'age': 30}")→{'name': 'Alice', 'age': 30}
更安全的做法仍是修复源头:让前端发标准 JSON,或在服务端加一层预处理(如用正则替换单引号为双引号,删注释)。
读取文件时最容易被忽略的编码与空白问题
json.load() 本身不处理 BOM 和首尾空白,但错误常被归咎于“JSON 格式不对”。真实原因往往是:
- 文件以 UTF-8 with BOM 保存,开头三个字节
\xef\xbb\xbf让json.load()看到\ufeff{,直接报错 - 文件末尾有不可见空格或换行(尤其 Windows 编辑器保存时自动加的
\r\n) - 使用
open("file.json", "r")未指定encoding,依赖系统默认编码(Windows 上可能是 cp1252)
正确做法:
- 总是显式声明编码:
open("file.json", "r", encoding="utf-8-sig")(utf-8-sig自动剥离 BOM) - 若文件可能含多余空白,先读取再 strip:
json.loads(f.read().strip()) - 不要依赖编辑器“看起来正常”——用
xxd file.json | head或 VS Code 的“显示不可见字符”功能确认实际字节
真正棘手的情况是 JSON 片段流(如 SSE、日志行),此时需要按行切分再逐行解析,而不是一股脑 json.loads() 整个响应体。

















