JSONDecodeError根本原因是输入违反RFC 8259规范,常见于BOM头、控制字符、单引号、末尾逗号等;应先strip清洗、再用json.loads()解析,并严格try-except捕获JSONDecodeError,禁用ast.literal_eval()替代。

遇到 json.loads() 报 JSONDecodeError 怎么办
直接用 json.loads() 解析不可信输入(比如用户提交、网络响应)必然踩坑。错误不是“没写 try-except”,而是没预判常见破坏点:BOM 头、控制字符、不合法 Unicode 转义、末尾逗号(Python 3.12+ 才支持)、单引号代替双引号。
安全做法是先做轻量清洗,再解析:
- 用
string.strip()去首尾空白(含 BOM) - 对已知来源含单引号的场景,可谨慎替换
'→",但必须确保无嵌套引号或转义干扰(比如"{'name': \"O'Reilly\"}') - 用
re.sub(r'[\x00-\x08\x0b\x0c\x0e-\x1f]', '', s)删掉 JSON 不允许的控制字符(\x09制表符和\x0a换行符是合法的) - 始终包在
try/except json.JSONDecodeError:里,不要捕获宽泛的Exception
为什么不能用 ast.literal_eval() 替代 json.loads()
ast.literal_eval() 看似能解析类似 JSON 的字符串,但它接受 Python 字面量语法:允许 True/False/None、单引号字符串、无引号键(如 {key: 42}),而这些在标准 JSON 中非法。这会造成语义错位——你以为在解析 JSON,实际在执行 Python 字面量解析,可能绕过你对键名/值类型的预期校验。
更危险的是,某些服务端返回的“类 JSON”响应(如 Django 的 JsonResponse 严格输出标准 JSON),若前端误用 ast.literal_eval(),后续对接其他语言客户端时会因格式不一致出问题。
结论:ast.literal_eval() 是 Python 内部数据交换的工具,不是 JSON 解析器。坚持用 json.loads(),配合清洗和异常处理。
需要保留原始键顺序时,json.loads() 的 object_hook 怎么写
Python 3.7+ 的 dict 本身保持插入顺序,所以多数情况无需额外操作。但如果你要兼容旧版本,或需要把 key 全部转成小写、加前缀等,就得用 object_hook。
注意陷阱:object_hook 函数接收的是已解析的 dict(非原始字符串),且只作用于最外层及每个嵌套对象,不递归处理 list 中的 dict —— 它只在每次解析完一个 JSON 对象字面量时触发一次。
示例(转小写键):
def lower_keys(d):
return {k.lower(): v for k, v in d.items()}
<p>data = json.loads('{"Name": "Alice", "AGE": 30}', object_hook=lower_keys)</p><h1>→ {'name': 'Alice', 'age': 30}</h1><p></p>
如果 JSON 里有数组包含对象(如 [{"X": 1}, {"Y": 2}]),object_hook 仍会分别作用于每个 {"X": 1} 和 {"Y": 2},没问题;但它不会自动处理 list 本身。
从文件读取 JSON 时,编码和换行符怎么处理才不出错
常见错误是直接 open(path).read() 后丢给 json.loads(),忽略文件编码和行结束符。Windows 的 \r\n 在 JSON 中合法,但 UTF-8-BOM(\ufeff)会导致 JSONDecodeError: Expecting value。
正确方式是明确指定编码,并让 json.load() 直接处理文件对象:
- 永远用
encoding='utf-8'打开,即使你认为是 ASCII —— 避免系统 locale 影响 - 优先用
json.load(f)(传 file object),而不是json.loads(f.read());前者内部会处理 BOM,后者不会 - 如果必须用
loads(),先用codecs.BOM_UTF8检查并切掉开头的 BOM 字节
没有万能编码检测。别依赖 chardet 自动猜 —— JSON 规范只允许 UTF-8/UTF-16/UTF-32,而绝大多数生产环境只应使用 UTF-8。
解析 JSON 的真正难点不在语法,而在你是否清楚输入来源的边界:它是不是真的 JSON?谁生成的?有没有中间代理篡改过?这些问题比选哪个函数重要得多。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











