云计算百科
云计算领域专业知识百科平台

写给工程师的 JSON 数据设计指南:从“能用”到“好用、耐用、可进化”

很多项目里,JSON 只是个“数据容器”:字段往里一塞,接口就算通了。但真正经得起时间、团队、业务变化考验的 JSON,需要把“表示、约束、演进、效率、安全”一起考虑。下面这篇从实践出发,讲清楚设计 JSON 时该想什么、怎么取舍、如何落地。


一、先回答三个基本问题

1)这份 JSON 的边界是什么?
它是一个领域对象(如 User)、一个聚合视图(统计报表)、还是传输协议负载(API 的 request/response)?边界决定了字段粒度、是否需要冗余、以及能否被复用。

2)读写路径是谁?
是 JS 前端直读?还是 Python 批处理?不同语言对数值精度、日期解析、大小写习惯都不一样,设计时要预想“消费者”的真实能力与坑点。

3)生命周期怎么演进?
这份 JSON 以后会扩展吗?向后兼容是否必须?版本如何管理?如果一开始就接受“会变化”,你就会主动为未来留扩展位与约束机制。


二、命名与结构:可读、稳定、可演进

命名风格统一

  • 前后端一体化项目常用 camelCase;数据仓库/ETL 往往偏好 snake_case。关键在“统一”,混用最难维护。

  • 避免缩写(usr_id 不如 user_id),避免语义含糊(value、data)。

  • 字段名建议稳定,新增胜过重命名(重命名会破坏兼容性)。

对象 vs 数组

  • 表达“具名属性集合”用对象;表达“有序集合”或“同质条目列表”用数组。

  • 非必要别把对象强行塞进数组第 0 位取用,这会让语义与索引耦合。

嵌套与扁平

  • 面向写多读少、需要领域边界清晰的,用嵌套(可读、语义自洽)。

  • 面向分析/检索、读多写少的,用扁平(便于建索引和聚合)。

  • 复杂场景可采用“外部扁平 + 内部嵌套”混合:对外一层扁平可检索,业务子对象内部保留语义结构。

示例

{
"user_id": "u_123",
"profile": {
"full_name": "Ada Lovelace",
"locale": "en-GB"
},
"roles": ["admin", "editor"],
"created_at": "2025-08-14T10:08:00Z",
"meta": { "version": 3, "source": "import" }
}


三、可兼容的演进策略

“向后兼容”优先级最高

  • 新增字段不影响老读者;删除/重命名则高危。要删除时,先“双写+弃用标记(deprecated)”一个版本周期,再宣布下线。

  • 缺失 vs 空值:缺失表示“未知/未提供”,null 表示“明确无值”。区分它们能显著减少歧义。

版本化

  • 细粒度场景用能力探测(“如果有 field_x 就使用”);

  • 严格契约用模式版本("schema_version": 2),或在 API 路径中标注版本(与载荷里的 "version" 各司其职)。

  • 设计扩展位:预留 meta 或 x-* 命名空间存放非核心字段,避免污染主模型。

变更表达

  • 部分更新优先考虑 JSON Patch(RFC 6902)或 JSON Merge Patch(RFC 7386),更小、更明确,可审计。


四、类型与格式:把坑填在设计阶段

布尔与枚举

  • 明确枚举列表:例如 status: "pending" | "active" | "suspended",避免布尔地狱(is_ok, is_valid, is_ready 同时出现)。

  • 复杂状态用枚举 + reason 细化。

数值与精度

  • 金额/利率/大整数不要用二进制浮点。三种做法:

  • 字符串传输("amount": "136500.25"),由消费端严格解析;

  • 整数最小单位(分/厘),如 13650025;

  • 定点小数(规定精度位数)。

  • 选择一种并写进契约。

时间与时区

  • 推荐 ISO 8601 UTC:"2025-08-14T10:08:00Z";

  • 避免无时区的裸日期时间。仅日期用 "YYYY-MM-DD",仅时间用 "HH:MM:SS" 并说明时区上下文。

  • 需要区间就用 start_at / end_at,避免复用单字段承载多义。

二进制与大文本

  • 图片、PDF 不直接塞 base64(膨胀+内存压力),传 URL + 摘要哈希;需要内嵌时加上 media_type 与 sha256。

国际化(i18n)

  • 文本多语言:要么多条记录分语言,要么结构化字段:

"title": { "zh-CN": "标题", "en-US": "Title" }

  • 统一 locale 标记,遵循 BCP 47(如 zh-CN)。


五、归一化 vs 冗余:为读写成本做减法

  • 强一致、高变更率:倾向归一化(用 id 关联,减少重复更新),但读取需要二次查询。

  • 读多写少、聚合展示:允许适度冗余(复制少量快变字段),换取读取直达。

  • 经验法则:冗余字段要标注来源与更新时间:"seller_name": "…", "seller_snapshot_at": "…",清楚“快照语义”。


六、错误与元信息:契约要友好

错误对象(避免只返回字符串)

{
"error": {
"code": "INVALID_ARGUMENT",
"message": "amount must be >= 0",
"details": [{ "field": "amount", "rule": "min", "min": 0 }]
},
"trace_id": "req-7f3c…"
}

  • 给机器可解析的 code,给人可读的 message,加 trace_id 便于排障。

  • 成功响应也建议有 meta:分页信息、总数、游标等。

分页/列表

  • 大集合尽量游标(next_cursor)而不是页号(避免数据漂移)。

  • 明确上限(如 limit<=100),防止滥用导致内存爆。


七、校验与文档:用工具把“约定俗成”变成“强约束”

JSON Schema(Draft 2020-12 等)

  • 为每个公开结构提供 schema,并在 CI 中校验。

  • 把示例和边界条件写进测试夹具。

  • 推荐理念:宽进严出(输入端更宽容,输出端更严格)。

落地工具

  • Node.js:Ajv;Python:Pydantic/JsonSchema 校验;Java/Kotlin:Jackson + Bean Validation;Go:jsonschema + 自定义校验;Rust:serde + validator。

  • 为 Schema 加注释(description),把文档生成自动化。

最小样例(片段)

{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://example.com/schemas/order.json",
"title": "Order",
"type": "object",
"required": ["order_id", "items", "amount", "created_at"],
"properties": {
"order_id": { "type": "string", "pattern": "^ord_[a-zA-Z0-9]{8,}$" },
"items": {
"type": "array",
"minItems": 1,
"items": {
"type": "object",
"required": ["sku", "qty"],
"properties": {
"sku": { "type": "string" },
"qty": { "type": "integer", "minimum": 1 }
},
"additionalProperties": false
}
},
"amount": { "type": "string", "pattern": "^[0-9]+(\\\\.[0-9]{2})?$" },
"created_at": { "type": "string", "format": "date-time" }
},
"additionalProperties": false
}


八、性能与规模:从“请求一次”到“跑得稳”

体积控制与可流式

  • 大列表使用 NDJSON/JSON Lines(一行一条记录)便于流式处理与增量写入。

  • 合理分页、字段选择(fields=…)、与压缩(传输层开启 gzip/br)。

  • 结果集可分层:summary(轻)与 details(重)分离。

顺序与确定性

  • JSON 对象键无顺序保证;若你需要签名/去重,使用 Canonical JSON/排序后的键 进行哈希。

  • 对外宣称“顺序稳定”的数组,务必定义稳定排序键与并发写入策略。


九、安全与健壮性:别让 JSON 成为攻击面

  • 数字溢出/精度丢失:JS 的 Number 是双精度浮点,大整数会丢精度。关键数值用字符串或 BigInt 方案。

  • 原型污染:在 JS 反序列化时拒绝 __proto__、constructor 等魔法键。

  • 字段白名单:反序列化到强类型对象时启用白名单/additionalProperties:false。

  • 限流与尺寸:限制最大载荷与最大数组长度,避免 JSON 炸弹(深嵌套/巨数组)。

  • 签名与校验:重要数据体可做 HMAC/签名,配合 canonical 化避免“重排”攻击。


十、一个从 0 到 1 的设计流程示例

以“订单导出服务”为例,你可以这样走:

  • 目标与消费者:供前端分页查看、也供数据团队批量拉取。

  • 结构选择:对外分页 API 用对象+数组;离线导出提供 NDJSON。

  • 字段与语义:金额字符串两位小数;时间一律 UTC ISO 8601;商品条目为数组,qty 整数。

  • 扩展与版本:根对象含 schema_version 与 meta;弃用字段先双写。

  • 约束与文档:编写 JSON Schema,CI 校验,自动生成接口文档;提供最小样例与错误样例。

  • 性能与安全:分页上限 100,数组长度上限 1000,返回体压缩,服务端设总超时;对导出任务结果做 canonical JSON + 哈希校验。


  • 十一、易错与反模式速记

    • 把金额用浮点数;

    • 混用大小写命名;

    • 一个字段多重语义(既放“创建时间”又偶尔放“更新时间”);

    • 用 null 表示“缺失”和“明确无值”两种不同含义;

    • 返回纯字符串错误信息、缺少错误码;

    • 把大文件/图片直接 base64 塞进响应;

    • 随意重命名字段、无版本策略;

    • 让对象键顺序承担语义。


    末尾清单(Checklist)

    • 命名统一且语义明确

    • 类型清晰:金额/大整数有精度策略;时间有时区

    • 缺失 vs null 语义区分

    • 结构选择:对象/数组/嵌套/扁平的取舍有理由

    • 预留扩展位(meta/x-*),有版本/弃用策略

    • 错误模型有 code/message/details/trace_id

    • 分页与限流规则明确(页号或游标、上限)

    • JSON Schema 覆盖 & CI 校验 & 示例齐全

    • 大数据量有 NDJSON/流式方案与压缩

    • 安全:白名单、深度/大小限制、canonical + 签名(必要时)

    赞(0)
    未经允许不得转载:网硕互联帮助中心 » 写给工程师的 JSON 数据设计指南:从“能用”到“好用、耐用、可进化”
    分享到: 更多 (0)

    评论 抢沙发

    评论前必须登录!