智核技术笔记

返回文章列表

程序启动时读一份 JSON 配置,最怕的不是文件不存在,而是文件能打开、内容却少了一个字段,或者端口被写成了字符串。程序继续往下跑,等到真正用到这个值才报错,排查时已经离配置文件很远了。

下面的做法只使用 Python 标准库。当前文档以 Python 3.14 为准:json.loads 在文本不是合法 JSON 时抛出 json.JSONDecodeError,这个异常带有行号和列号。示例在 Python 3.14.3 里运行过。

先约定配置长什么样

一份本机服务配置可以是这样,保存为 app.json,编码用 UTF-8,不要带注释:

{
  "name": "笔记站点",
  "port": 8080,
  "debug": false
}
json

JSON 没有注释语法。文件里出现 // 或 /* */,解析会直接失败。需要说明时,把说明写进旁边的文档,不要写进配置文件。

读取并检查字段

把下面的程序保存为 check_json_config.py,和 app.json 放在同一目录:

在该目录执行:

python check_json_config.py
bash

配置正确时输出:

配置可用:笔记站点,端口 8080
text

这里有两个容易忽略的点。

Path.read_text(encoding="utf-8") 把编码说死。Windows 上不写编码时,会随系统区域设置变化,同一份含中文的文件换一台机器就可能读失败。

bool 是 int 的子类。如果只写 isinstance(True, int),结果是真。端口写成 true 时会混过去,所以要先把布尔值单独拒绝。

常见错误

最后一项后面多一个逗号,是手写 JSON 最常见的错误。解析器会报告类似:

第 3 行,第 15 列,Illegal trailing comma before end of object
text

其他几类也值得在启动时拦住:

文件内容程序给出的结果
没有 port缺少字段:port
"port": true字段 port 应该是整数,不能是 true 或 false
"port": 70000端口超出 1 到 65535 的范围
最外层是数组最外层必须是对象
文件不存在找不到配置文件

只想先确认括号和引号,可以用标准库自带的命令。它默认会把非英文字符转成 \u 形式,阅读中文时加上 --no-ensure-ascii:

python -m json.tool --no-ensure-ascii app.json
bash

命令能打印出排好的内容,只说明语法正确,不说明字段齐全。字段和取值范围仍要由程序自己检查。

不要用 eval 去读配置。JSON 里出现计算表达式或函数调用时,那已经不是配置文件该做的事,也会把不该执行的内容带进来。

类型和编码还会碰到的情况

数字并不都是整数。json.loads("1.5") 得到的是浮点数,isinstance(1.5, int) 为假,所以上面的端口检查会拒绝 "port": 1.5。如果某个字段确实要小数,期望类型就写成 float,同时接受整数,因为 JSON 的 1 会变成 int 而不是 float。

空值是 None,不是空字符串。配置里写 "name": null 时,类型检查会要求字符串,从而在启动时失败。这比读到一半才发现名字是空的要早。

文件开头如果带了编辑器加的 BOM,utf-8 解码会失败,错误信息里会出现 BOM。解决办法是把文件另存为不带 BOM 的 UTF-8,而不是在程序里悄悄忽略所有解码错误。忽略错误会把后面的中文读成乱码,配置仍能「打开」,内容却是错的。

字段多出来时,这份示例选择保留,不报错。名称写错时,例如把 port 写成 ports,缺少字段的检查仍会抓住真正要用的 port。如果配置越来越长,再把允许的字段列成白名单,多出来的键也一并提示,避免拼写错误被静默留下。

检查通过之后再把配置交给真正启动服务的代码。不要在业务逻辑里重复写一套 if "port" in data。校验集中在 load_config,后面的代码就可以认为这三个字段一定存在,而且类型正确。

小结

读取 JSON 配置时,把「文件打不开」「不是 UTF-8」「语法不对」「字段缺失」「类型不对」「取值越界」分成几步报出来。错误出在启动阶段,并带上行号,比服务跑起来以后再查要直接得多。

使用 Python 读取与校验 JSON 配置文件
https://www.aicore.icu/blog/python-json-config
作者 智核技术笔记
发布于 2026年10月26日