4. JSON 配置实战:从语法到工程落地
JSON 这东西,现在几乎成了设备配置的通用语言。我最早接触它是在一个物联网网关项目里,当时团队还在用 XML 传配置,后来全切成了 JSON。为什么?说白了,JSON 够轻、够直观,机器解析快,人看着也不费劲。
这一章咱们就把它聊透。从最基础的语法,到嵌套结构怎么设计,再到用 Schema 做校验,最后用 Python 的 json 模块把配置读写跑通。嗯,都是实战里每天要用的东西。
4.1 JSON 语法基础——别在这些小地方翻车
JSON 的语法规则其实很少,但恰恰因为简单,很多人反而容易忽略细节。我在 code review 里见过最多的错误,就是多了一个逗号,或者 key 忘了加引号。
| 规则 | 说明 | 常见错误 |
|---|---|---|
| 键必须用双引号 | 单引号或不加引号都不合法 | {name: "value"} ❌ |
| 字符串必须用双引号 | 单引号包裹的字符串不合法 | {'key': 'value'} ❌ |
| 最后一个元素后不能有逗号 | 数组或对象的末尾逗号会报错 | [1, 2, 3,] ❌ |
| 值类型固定 | 字符串、数字、布尔、null、对象、数组 | 不能写 undefined 或函数 |
一个合法的 JSON 配置示例:
{
"device_id": "GW-2024-001",
"enabled": true,
"baud_rate": 115200,
"tags": ["production", "floor-3"],
"location": {
"building": "A",
"floor": 3
}
}
你看,结构很清晰。key 全是双引号,布尔值小写,数组和对象都规规矩矩。我建议你养成一个习惯:写完 JSON 先用在线工具或本地脚本验证一下,别等到设备解析报错才回头找。
4.2 嵌套结构设计——配置的骨架怎么搭
单层 JSON 只能应付最简单的场景。真实设备配置往往是多层嵌套的。比如一个串口参数,下面还有波特率、数据位、校验位。怎么设计才合理?
我个人习惯遵循一个原则:按功能域分层,每层只做一件事。
{
"device": {
"identity": {
"id": "GW-2024-001",
"model": "GW-Pro"
},
"network": {
"eth0": {
"dhcp": false,
"ip": "192.168.1.100",
"mask": "255.255.255.0"
},
"wlan0": {
"ssid": "factory-net",
"password": "encrypted_value"
}
},
"sensors": [
{"type": "temperature", "pin": 4, "interval_ms": 1000},
{"type": "humidity", "pin": 5, "interval_ms": 2000}
]
}
}
嵌套设计避坑指南:
- 嵌套不要超过 4 层,否则可读性急剧下降
- 数组里的对象结构要保持一致,别混搭
- 用
id或name字段做唯一标识,方便查找
我曾经在一个项目里见过 7 层嵌套的 JSON,光找配置项就花了半天。后来我强制团队把深层嵌套拆成多个文件,用 $ref 引用。嗯,这个后面讲 Schema 时会提到。
4.3 JSON Schema 校验——把错误挡在门外
设备配置最怕什么?怕格式不对、字段缺失、类型错误。这些问题如果等到设备运行时才发现,轻则重启,重则烧硬件。JSON Schema 就是用来提前做校验的。
说白了,Schema 就是配置的「模板」。你定义好规则,程序自动检查配置是否合规。
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "Device Configuration",
"type": "object",
"required": ["device_id", "network"],
"properties": {
"device_id": {
"type": "string",
"pattern": "^GW-\\d{4}-\\d{3}$"
},
"enabled": {
"type": "boolean",
"default": true
},
"baud_rate": {
"type": "integer",
"enum": [9600, 19200, 38400, 115200]
},
"network": {
"type": "object",
"required": ["eth0"],
"properties": {
"eth0": {
"type": "object",
"properties": {
"ip": {"type": "string", "format": "ipv4"},
"mask": {"type": "string", "format": "ipv4"}
}
}
}
}
}
}
注意: Schema 本身也是 JSON,所以同样要遵守 JSON 语法规则。我见过有人把 Schema 里的 required 写成了 require,结果校验一直不生效,排查了半天。
常用的校验关键字我列一下:
| 关键字 | 作用 | 示例 |
|---|---|---|
type |
指定数据类型 | "type": "integer" |
required |
必填字段列表 | "required": ["id", "name"] |
enum |
限定取值范围 | "enum": [9600, 115200] |
pattern |
正则匹配字符串 | "pattern": "^GW-" |
minimum/maximum |
数值范围 | "minimum": 0, "maximum": 100 |
format |
格式校验(ipv4、email 等) | "format": "ipv4" |
有了 Schema,你可以在配置加载前就做一次全面检查。我习惯在设备启动脚本里加一步 Schema 校验,通不过就直接报错退出,绝不带着错误配置运行。
4.4 Python 中的 json 模块——读写配置的瑞士军刀
Python 标准库的 json 模块,说实话,够用了。不需要装第三方库,开箱即用。我几乎每天都要跟它打交道。
4.4.1 读取配置
import json
with open("device_config.json", "r", encoding="utf-8") as f:
config = json.load(f)
print(config["device_id"])
print(config["network"]["eth0"]["ip"])
这里有个坑:json.load() 默认把文件里的所有内容读进来,如果文件里有 BOM 头(Windows 记事本干的坏事),就会报错。我建议打开文件时指定 encoding="utf-8-sig",能自动跳过 BOM。
4.4.2 写入配置
config = {
"device_id": "GW-2024-002",
"baud_rate": 115200,
"enabled": True
}
with open("output.json", "w", encoding="utf-8") as f:
json.dump(config, f, indent=2, ensure_ascii=False)
indent=2 让输出格式更可读,ensure_ascii=False 保证中文字符不被转义。这两个参数我每次都写,已经成肌肉记忆了。
4.4.3 用 Python 做 Schema 校验
Python 里做 Schema 校验,我推荐 jsonschema 库。它不是标准库,但 pip 装一下就行。
import json
from jsonschema import validate, ValidationError
schema = {
"type": "object",
"required": ["device_id", "baud_rate"],
"properties": {
"device_id": {"type": "string"},
"baud_rate": {"type": "integer", "enum": [9600, 115200]}
}
}
config = json.load(open("config.json"))
try:
validate(instance=config, schema=schema)
print("配置校验通过")
except ValidationError as e:
print(f"配置校验失败: {e.message}")
实战建议: 把校验逻辑封装成一个函数,每次加载配置时自动调用。我在项目里就是这么做的,上线两年没出过配置相关的故障。
4.5 知识体系总览
下面这张图把本章的核心脉络串起来了。从 JSON 语法出发,到嵌套结构设计,再到 Schema 校验和 Python 实现,每一步都是工程落地的关键环节。
好了,这一章的内容就这些。语法、嵌套、Schema、Python 实现,四个环节环环相扣。你写配置的时候,脑子里过一遍这个流程,基本不会出大问题。