JavaScript
浏览器和 Node 用 JSON.parse / JSON.stringify。HiJSON 也在这个语义上工作,所以你在树上看到的,基本就是 JS 解析后的值。
JSON.parse('{"a":1}')
JSON.stringify({ a: 1, b: undefined, c: () => {} })
// '{"a":1}' —— b、函数都丢了
undefined、函数、Symbol 不会出现在输出里。Date会被toJSON成 ISO 字符串,对端若当时间戳数字,对不上。NaN/Infinity变成null。- 大于
Number.MAX_SAFE_INTEGER的整数会丢精度。雪花 ID、订单号用字符串。 - 要保留大整数,得上
json-bigint一类库,或让接口改类型。
JSON.parse 的第二个参数 reviver 可以改键。写了 reviver 再和「原始文本」对比,别忘了自己改过。
Python
import json
json.loads('{"name":"测试"}')
json.dumps({"name": "测试"}) # 默认 ensure_ascii=True,中文变 \\u
json.dumps({"name": "测试"}, ensure_ascii=False)
- 对象变成
dict,数组变成list,true/false/null变成True/False/None。打印出来不像 JSON,不要把repr(dict)当 JSON 发出去(单引号)。 datetime不能直接dumps,要default=str或自定义 encoder。- 数字:JSON 里的整数在 Python 3 可以任意大;和 JS 对同一字段时,JS 可能已经漂了。
json.loads遇到重复键,后写的覆盖先写的,和多数 JS 引擎类似。
从日志复制 Python dict 到 HiJSON,先换成双引号,或在 Python 里 print(json.dumps(obj, ensure_ascii=False)) 再复制。
Go
type Order struct {
ID string `json:"order_id"`
Amount float64 `json:"amount"`
Note string `json:"note,omitempty"`
}
- 字段要导出(大写)才会被编码。小写字段静默消失,这是新手第一坑。
- tag 决定线上键名。
order_id和结构体里的ID不是一回事。 omitempty:零值不输出。false、0、""都会省掉。前端以为「没这个字段」,其实是零值被吃了。- 没有 tag 的数字,解码进
interface{}时是float64。整数 1 变成 1.0,再Marshal可能带小数点。 - 未知字段默认丢掉。要严格,用
Decoder.DisallowUnknownFields。
Go 的 json.Number 可以保原文。和前端对大整数时,结构体用 string 或 json.Number,不要用 int64 去接已经在 JS 里漂过的数。
对照表
| 情况 | JS | Python | Go |
|---|---|---|---|
| 字段值为 undefined / 未设置 | stringify 丢掉 | 没有 undefined,用缺键或 None | omitempty 可能丢掉零值 |
| 中文 | 默认原文 | 默认 \\uXXXX | 默认原文 |
| 超大整数 | 精度危险 | int 够用 | 看类型,interface 是 float64 |
| 时间 | Date → ISO 字符串 | 要自己编码 | time.Time → RFC3339 |
联调时怎么用 HiJSON
把各端实际发出的 body 分别贴进 HiJSON,不要对比「语言里的对象打印」。看三件事:
- 键在不在(omitempty / undefined)。
- 类型是数字还是字符串(金额、ID)。
- 列表长度是否被单对象吃掉。
路径对齐用 JSONPath,见 JSONPath 入门。结构约定可以写成 schema,见 JSON Schema。
常见问题
- 为什么 Go 收得到、Chrome 控制台里数字不对?
- 先在 HiJSON 里看原始文本里的数字有多少位。超过 15–16 位有效数字,JS 已经圆整。问题在浏览器,不在 Go。
- Java / PHP 呢?
- 套路类似:类型系统和「缺字段 / null / 零值」三套语义。先抓实际 JSON 文本,再对语言文档。不要用语言内部的 debug 打印当契约。