简介面向初学者的JSON完整示例项目包围绕JSON数据交换格式的语法规则与解析生成而设计适合Web开发入门者或需要快速掌握结构化数据处理的程序员。包内是完整的Eclipse工程JsonDemo共22个文件压缩包大小约2.88MB主要包含2个Java源文件、2个class文件、14个JSON相关Jar依赖、1份JSON笔记以及项目配置信息导入开发环境即可运行查看。示例覆盖了JSON对象、数组、嵌套对象和字符串/数字/布尔值等数据类型并展示了JavaScript中JSON.parse()与JSON.stringify()、Python中json.loads()与dumps()等常见解析生成方式笔记部分同步整理了键必须用双引号、末尾不能出现多余逗号等关键语法规则帮助读者避开常见错误。整个项目既有代码可调试又有笔记可对照能帮助初学者将JSON概念与实际项目串联起来。目前已有3577人学习值得下载参考。1. JSON 完整例子一份能直接抄进项目的示例合集让接口联调不再靠猜做接口联调最怕的不是逻辑写错而是两边对 JSON 结构的理解不一致。前端以为字段叫user_name后端返回username测试脚本里写死了三层嵌套线上实际返回五层排查起来全靠肉眼对字段。这份 JSON 完整例子合集是某开发者这些年做接口开发和数据交换时攒下的样本整理出来的基础类型、接口响应、错误格式、分页结构、配置文件、Schema 校验每个例子都带注释和适用场景说明。适合正在写接口文档的后端、做联调的前端、跑数据清洗的分析师以及想统一接口规范的团队。它的价值不是教你 JSON 是什么而是给你一堆能直接抄的结构模板把调试时间花在真正要解决的业务上。2. JSON 的结构边界六种数据类型与三组高频误用先看清再动手2.1 六种数据类型的取值边界哪些能存、哪些会翻车JSON 总共只有六种数据类型string、number、boolean、null、array、object。这句话我每次给新同事讲接口规范都要重复一遍因为很多人会把 Date、undefined、NaN 这些语言层面的类型直接写进 JSON解析端要么收到一串字符串要么直接抛异常。下面这段是从例子包 01-basic 目录里摘出来的基础示例一段 JSON 覆盖全部六种类型{ project: 订单服务, version: 1.2, is_active: true, owner: null, tags: [api, bff, backend], dimensions: { width: 1920, height: 1080 } }第一行 project 是字符串必须用双引号包裹单引号在严格解析器里直接报错version 是数字JSON 里没有 int 和 float 之分1.2 和 1 都叫 number这也是后面会讲到的精度问题的根源is_active 是布尔值只能写 true 或 false写成 True 或 1 在多数解析器里都会翻车owner 是 null表示这个字段存在但值为空不是 0也不是空字符串tags 是字符串数组数组里元素类型在生产环境建议保持一致dimensions 是嵌套对象对象里面再套对象。这六种类型自由组合基本覆盖了日常 95% 的数据交换场景。边界和误用主要集中在三处。第一是 number 的精度问题超过 2^53 的整数比如雪花 ID、订单号在 JavaScript 里用 JSON.parse 解析会丢精度Python 的 json 模块能转成 int但数据一旦经过消息队列再被前端消费数字就不是原来那个了。常见做法是把这类大整数序列化成字符串代价是前端拿到后不能直接做数值运算大多数业务场景下完全够用。第二是字符串的转义JSON 字符串里不能有裸换行和裸双引号必须写成 \n 和 这个坑我会在第 5 章专门展开。第三是 null 和字段缺失的语义区别很多人把没有这个字段和这个字段是空混为一谈在序列化层会引发一连串问题。提示JSON 不允许注释也不允许尾逗号。拿过来就报错的 JSON大概率是写了 // 注释或者最后一行多了个逗号。有的解析器宽松能过换一种语言的解析器就翻车所以标准写法是最省事的。2.2 示例包的文件组织六个目录对应六类业务场景这份例子包解压后是 json-examples 目录按使用场景拆成了六个子目录每个目录里有 README 说明该目录下的例子适用哪种业务。比起把几十段 JSON 堆在一个大文件里按场景拆文件的组织方式查起来快得多引用也方便json-examples/ ├── 01-basic/ 基础类型与嵌套结构示例适合刚接触 JSON 的人 ├── 02-api/ 接口请求/响应体示例含分页、排序、筛选 ├── 03-error/ 错误响应格式示例含错误码与字段级错误 ├── 04-config/ 配置文件示例含环境切换与敏感信息处理 ├── 05-schema/ JSON Schema 定义示例配套校验脚本 └── 06-realworld/ 综合场景示例比如订单详情、用户中心我的使用习惯是把它当字典查而不是从头读到尾。比如正在设计分页接口直接打开 02-api/pagination.json 看字段怎么组织要统一错误返回结构翻开 03-error 目录对照着写想把接口返回值在测试环境里自动校验一遍就拿 05-schema 里的 Schema 文件配上校验脚本。这个例子包解决的痛点就是临时需要一段 JSON 结构却总得现场拼或者翻旧项目找省下来的时间用在真正有难度的业务逻辑上。3. 把 JSON 写进真实接口响应包装、分页与错误码的完整可抄样例3.1 响应体包装与分页参数设计字段先定规矩联调才不扯皮接口响应体最怕两种风格一种是每个接口的字段命名随心情另一种是返回结构混乱数组和对象来回换。我一般会在项目里定一个统一的包装结构code、message、data 三个顶层键。code 为 0 表示成功非 0 表示业务错误message 是给人看的提示data 装真正的业务数据。这样调用方只要判断 code再按 data 的结构取数据不用每换一个接口就重新适应一套结构。例子包 02-api/response.json 里的分页接口是这样写的{ code: 0, message: success, data: { list: [ { id: 10231, order_no: ORD20250117001, amount: 299.00, status: paid, created_at: 2025-01-17T14:23:0908:00 } ], page: 1, page_size: 20, total: 356 } }这里有几个值得注意的约定。第一id 用字符串而不是数字这是精度问题的前置预防所有 ID 字段一律按字符串处理调用方原样透传就行。第二时间字段用 ISO 8601 带时区偏移的写法2025-01-17T14:23:0908:00不用毫秒时间戳因为人类可读性差排查问题时还得先转换一遍只要格式统一字符串比对或者转成时间对象排序都没有歧义。第三分页参数 page 和 page_size 是请求侧传进来的total 是响应里的总量前端靠这三件套渲染分页组件就够了不用再额外发一次 count 请求。分页还有一种 cursor 翻页方式适合信息流这种实时性强、数据量大的场景。page 翻页的问题是新增数据后页码会漂移上面看过的内容被顶下去了cursor 用一段不透明字符串记录上次翻到的位置下一页从那个位置往后取{ data: { items: [{id: 1001, title: 示例文章}], next_cursor: eyJpZCI6IjEwMDEifQ } }cursor 对调用方来说就是个黑匣子后端怎么编码都行只要保证下一页传回来的 cursor 能接上上一页的位置即可。管理后台这种以稳定为第一优先级的场景用 page 就好别上来就上 cursor——游标的过期、失效、数据重复这些细节复杂度是要用真实的联调时间还的。3.2 错误响应标准化错误码、trace 与字段级错误信息错误响应比成功响应更容易被忽视等线上出了事才知道它的重要性。最常见的问题是错误信息只有一串英文堆栈或者一句系统错误联调时根本猜不到是哪个参数出了问题。我常用的错误响应方案长这样{ code: 40001, message: 参数校验失败, trace_id: a3f8c2e1-9b4d-4f6a-8c2e-1a2b3c4d5e6f, details: [ { field: amount, error: 金额必须大于0, value: -10 } ] }code 是业务错误码我习惯分段管理4xxxx 表示调用方参数问题5xxxx 表示服务端内部问题前端根据错误码的段位决定是提示用户还是走降级逻辑。trace_id 是一次请求的链路标识后端日志里按这个字段能捞到完整链路调用方拿到后贴在错误报告里是定位线上问题最快的钥匙。details 数组放字段级错误每个元素包含字段名、错误原因、出问题的原始值——有了值这一项很多我明明传对了的争论可以当场平息把截图往群里一贴谁传错了一目了然。注意错误响应里任何时候都不要返回堆栈信息。堆栈留在服务端日志里返回给调用方既暴露内部实现对解决问题也没有帮助只会让前端在 console 里刷出一屏看不懂的英文。4. 用 JSON Schema 给数据上约束订单示例与 Python 校验脚本实战4.1 Schema 常用关键字拆解从结构声明到值域校验JSON 本身不约束结构同一个字段有时返回字符串有时返回数字联调阶段全靠人肉盯。JSON Schema 就是给 JSON 写类型声明的规范它定义字段该是什么类型、哪些字段必须有、值域范围是什么解析端可以用它自动校验。例子包 05-schema 目录里有一个完整的订单 Schema我把核心部分贴出来{ $schema: http://json-schema.org/draft-07/schema#, type: object, required: [order_no, amount, status], properties: { order_no: { type: string, pattern: ^ORD\\d{11}$ }, amount: { type: number, minimum: 0, exclusiveMinimum: true }, status: { type: string, enum: [pending, paid, shipped, cancelled] }, items: { type: array, minItems: 1, items: { type: object, required: [sku, qty], properties: { sku: { type: string }, qty: { type: integer, minimum: 1 } } } } }, additionalProperties: false }逐个关键字说。$schema 声明规范版本不同版本的写法有差异我统一用 draft-07兼容性最好。type 声明类型object、array、string、number 这些和 JSON 类型一一对应。required 是个数组列出必须存在的字段校验时缺一个就报错。pattern 是正则表达式这里的 ^ORD\d{11}$ 表示必须以 ORD 开头后跟 11 位数字。minimum 和 exclusiveMinimum 配合控制数值下界金额必须大于 0 就靠它们实现。enum 把 status 锁死在四个合法取值上不会出现拼写错误导致的 paid 和 payed 并存。items 用来约束数组里的每个元素这里要求每一项都是对象且必须包含 sku 和 qty。additionalProperties 设为 false意味着没在 properties 里声明过的字段直接校验失败——这能让接口结构长期保持干净但代价是加字段时必须同步改 Schema属于有意为之的约束。4.2 Python 校验实操把 Schema 放进测试流程结构变化第一时间暴露Schema 写出来是要用的。Python 里最常用的是 jsonschema 库我一般会在测试环境写一个校验脚本接口每次返回的数据先过一遍 Schema结构一变测试就红不需要等前端来问字段是不是改了import json from jsonschema import Draft7Validator # 第一步加载 Schema 定义文件 with open(05-schema/order_schema.json, r, encodingutf-8) as f: schema json.load(f) # 第二步加载待校验的接口响应样例 with open(02-api/order_response.json, r, encodingutf-8) as f: data json.load(f) # 第三步用 iter_errors 收集所有违规点而不是遇到第一个错误就停 errors sorted( Draft7Validator(schema).iter_errors(data), keylambda e: list(e.path) ) if not errors: print(结构校验通过) else: for err in errors: path ..join(str(p) for p in err.path) or $ print(f[{path}] {err.message})脚本逻辑分四步先读 Schema 文件再读要校验的响应样例然后用 Draft7Validator 实例的 iter_errors 方法收集全部错误最后按字段路径排序后逐条打印。之所以用 iter_errors 而不是 validate是因为 validate 遇到第一个错误就抛异常iter_errors 能一次性拿到整份 JSON 的所有违规点跑一次改一次。打印格式里的 path 是字段在 JSON 里的完整路径比如 items.0.sku配合 err.message 能精确定位到具体字段比翻日志肉眼对结构高效得多。集成方式也很简单把这个脚本包成一个测试用例放进接口测试套件每次联调前跑一遍再进一步就是接入 CI接口文档有变更时先验证所有响应样例仍然符合 Schema不符合就直接拦下构建。一套做下来字段改名、类型漂移这类问题在发布前就暴露了而不是上线后用线上报错来提醒你。还有个依赖版本的坑要提醒jsonschema 库不同版本支持的关键字范围不一样draft-04 和 draft-07 对 exclusiveMinimum 这类关键字的写法要求都不同。我一般固定用 jsonschema 4.x 配合 draft-07Schema 文件开头的 $schema 字段和库版本保持一致能省掉一堆莫名其妙的报错。5. JSON 避坑手册五个高频翻车场景与排查记录附修复写法5.1 大整数精度丢失订单号解析出来对不上现象后端返回的雪花 ID 是 12345678901234567890调用方用 JavaScript 的 JSON.parse 一解析变成了 12345678901234567000拿去查数据库就查不到了日志里的数字和实际存储的数字对不上。原因JSON 的 number 在主流语言里默认按双精度浮点存储超过 2^53 的整数保不住精度。Python 的 json 模块能解析成高精度 int但数据但凡经过一道 JavaScript 或者某些 JSON 解析库数字就悄悄变了。我曾排查过一个诡异问题链路日志里数字是对的数据库里存的也是对的但前端提交回来的查询条件变了最后定位就是中间层用 JSON.parse 转了一道。解决约定所有可能超过 2^53 的 ID雪花 ID、大订单号、流水号一律序列化成字符串。后端序列化时把 id 字段用 str() 包一层再返回调用方原样透传不做数值运算。这是行业里的共识做法不是某个框架的偏好一开始就把约束写进接口文档能省掉后续大批改造。5.2 字符串转义换行和引号让 JSON 结构直接崩掉现象手写拼接 JSON值里如果有换行或者双引号解析直接报Expecting value: line X column Y而且报错行号跟实际有问题的行总是对不上肉眼找半天也看不出哪里坏了。原因JSON 字符串里换行必须写成 \n双引号必须写成 反斜杠必须写成 \。手写拼接时这些字符原样被塞进字符串结构就被破坏了——换行符被当成字段分隔符双引号被当成字符串边界解析器当然疯掉。解决永远不要手动拼 JSON。Python 用 json.dumpsJavaScript 用 JSON.stringify语言自带的序列化方法会把所有转义处理干净。如果是从第三方拿到的 JSON 文本报解析错误把文件丢进带行号提示的 JSON 检查工具里先定位到具体行再人工检查那一行里有没有裸换行或者未转义的引号。5.3 嵌套层级过深递归解析直接爆栈现象一个配置 JSON 嵌套了三四十层json.load 能正常解析但用递归函数遍历处理时报RecursionError: maximum recursion depth exceeded程序直接中断。原因Python 默认递归深度上限是 1000嵌套层级深加上递归函数每层占用的栈空间触顶是迟早的事。嵌套层级一旦上了几十层递归遍历是第一个扛不住的。解决两条路。第一条是临时调高上限sys.setrecursionlimit(5000)但别设太大否则进程可能直接崩溃第二条是改成迭代遍历用栈手动模拟递归的压栈和出栈。我自己遇到深层嵌套的场景会直接用迭代方案一劳永逸不依赖调递归上限这种治标不治本的做法。5.4 null 与字段缺失两种空值的语义混淆现象接口返回 null前端拿到后渲染成了字符串 null或者以为字段没值就跳过渲染结果页面少了关键区块用户看到的界面不完整。原因null 表示字段存在但值为空字段缺失表示这个字段不存在。不同的序列化库、不同的后端语言对 None 和 undefined 的处理方式不一样到了前端就出现语义分裂——有的框架把 null 转成字符串有的框架保留为 null还有的干脆过滤掉。解决在接口规范里明确写清楚可选字段没值的时候返回 null 还是不返回。我一般建议统一返回 null因为前端判断 null 比判断 undefined 要心里有数同时在序列化层强制这种行为不依赖框架默认行为。另外null 和空字符串千万别混用该是字符串的字段用 该是空值的用 null各干各的混用会让前端的条件判断越写越乱。5.5 大文件一次性载入内存直接飙满现象解析一个 200MB 的 JSON 日志文件Python 进程内存一路冲到 1GB 以上机器开始卡顿最后进程被系统 OOM 杀掉。原因json.load() 会把整个文件读进内存构建成嵌套的字典和列表对象树。JSON 文本本身 200MB转成 Python 对象后还有对象头、引用等额外开销内存膨胀个三五倍很正常小机器扛不住。解决换成流式解析。Python 用 ijson 库按路径逐段取数据只保留需要的字段边读边处理或者先用工具把大文件按顶层键拆成多个小文件再逐一处理。命令行工具 jq 虽然好用但它同样会把整个文件载入内存超大文件照样扛不住——真要处理海量 JSON还是得走流式方案把一次读全改成按需取用。6. 进阶技巧用 JSON Patch 做增量更新把接口交互量降到十分之一更新类接口最常见的写法是把整个对象 PUT 过去字段多的时候一次请求传几十 KB改一个状态位也得捎上全量数据。JSON Patch 是另一种思路只传变更的操作指令接收方在基线文档上按指令打补丁。这个规范叫 RFC 6902支持 add、remove、replace、move、copy、test 六种操作覆盖了绝大多数字段级变更需求| 操作 | 作用 | | add | 在指定路径插入新值 | | remove | 删除指定路径的值 | | replace | 替换指定路径的值 | | move | 把值从一处移到另一处 | | copy | 复制值到指定路径 | | test | 断言指定路径的值等于给定值 |例子包 06-realworld 里有一段订单状态流转的 patch把状态从 paid 改成 shipped、补一个运单号、删掉废弃的备注字段[ { op: replace, path: /status, value: shipped }, { op: add, path: /tracking_no, value: SF1234567890 }, { op: remove, path: /remark } ]Python 端用 jsonpatch 库的 apply_patch 就能把补丁打到对象上不修改原对象而是返回一份新的字典import json from jsonpatch import apply_patch # 读基线文档请求方和服务端必须持有同一份 with open(order_20250117.json, r, encodingutf-8) as f: order json.load(f) # 只传差异操作改状态、补运单号 patch [ {op: replace, path: /status, value: shipped}, {op: add, path: /tracking_no, value: SF1234567890} ] # apply_patch 不修改原对象返回新字典保证基线文档不被污染 updated apply_patch(order, patch) print(json.dumps(updated, ensure_asciiFalse, indent2))JSON Patch 有个前提请求方和服务端必须持有同一份基线文档路径才能对上否则补丁会打到错误的位置。写操作密集、对象频繁整体更换的场景里这个前提不好维护老老实实传全量反而简单。我会在补丁里额外带一条 test 操作作用在状态字段上相当于乐观锁状态不是预想值就直接失败避免我改的时候别人已经改过的覆盖问题。从那以后我每次设计更新类接口都会先问一句这个场景到底要全量还是差异然后打开例子包里 06-realworld 的 JSON Patch 示例按路径改字段再补一条 test 断言接口交互量肉眼可见地降下来联调也没再出过到底谁改了这条数据的扯皮。这套 JSON 完整例子合集就在资源包里拿回去按目录索引找到对应场景直接抄字段改结构就行。希望帮到你。本文还有配套的精品资源点击获取