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 实现,每一步都是工程落地的关键环节。

JSON 配置实战知识体系 JSON 配置实战 JSON 语法基础 嵌套结构设计 JSON Schema 校验 Python json 模块 键值对规则 数据类型 json.load() json.dump() type/required enum/pattern 核心思路:语法正确 → 结构合理 → 校验严格 → 代码可靠 每一层都是下一层的基础,跳过任何一步都会在工程中埋坑

好了,这一章的内容就这些。语法、嵌套、Schema、Python 实现,四个环节环环相扣。你写配置的时候,脑子里过一遍这个流程,基本不会出大问题。