go标准库json解析默认丢失大数精度,须用json.number接收关键id字段并显式转换;第三方数据需usenumber()配合类型断言;前端必须字符串化超53位数字,框架封装会绕过自定义解码逻辑。

GoLand 项目里写 JSON 解析,不加干预就一定会丢大数精度——不是 IDE 问题,是 Go 标准库默认行为,必须在代码层显式处理。
struct 字段用 json.Number 接收关键 ID 字段
这是最轻量、最可控的方案,适合你已知哪些字段可能超 2^53 - 1(比如雪花 ID、微秒时间戳、TraceID)。
- 字段声明为
ID json.Number `json:"id"`,不是int64也不是string - 取值时调
u.ID.Int64()——它内部检查溢出和非法字符,比strconv.ParseInt(u.ID.String(), 10, 64)少一层 error 处理 - 如果 ID 可能超
int64(如 128 位),直接用u.ID.String()拿原始文本,传给前端或存 DB 都安全 - 别对
json.Number做算术运算;要算先转,且必须检查返回 error -
json:",string"和json.Number不能混用:前者只对string类型生效,后者本身就是字符串别名
用 map[string]interface{} 时必须调 UseNumber()
当你接第三方 Webhook、泛型数据、或还没定义结构体时,map[string]interface{} 是常见选择——但默认会把所有数字塞进 float64,精度当场报废。
详细的 Three.js 3D 图形参考,涵盖场景设置、相机、几何体、材质、光照、动画、控制器、加载器、数学工具和调试。
- 别用
json.Unmarshal直接解到map;改用json.NewDecoder(r.Body).UseNumber()手动解码 - 从
map取值后,必须先断言为json.Number:v, ok := m["id"].(json.Number),再调.Int64()或.String() -
UseNumber()不自动穿透嵌套的map或[]interface{};子层字段仍需手动识别和转换 -
json.RawMessage不是救星——它只是缓存字节,后续一旦调json.Unmarshal,照样掉进float64陷阱
前端发的是裸数字,Go 层再怎么写都救不回来
精度丢失的第一道关卡在 JS 端。哪怕你在 GoLand 里写得再严谨,如果前端发的是 {"id": 12345678901234567890}(没引号),那这个数字在浏览器里已被 JSON.stringify 转成 float64,Go 收到的已是失真值。
- 前后端必须约定:所有可能超
2^53 - 1的字段,前端必须以字符串形式发送,即{"id": "12345678901234567890"} - 后端用
string字段 +json:",string"标签也能接,但语义不如json.Number清晰(后者明确表示“这是数字,只是暂不解析”) - 别指望靠
json.Number或string字段去“修复”前端发错的裸数字——Go 没法还原 JS 已丢失的精度
最容易被忽略的一点:框架封装(如 Gin 的 ctx.BindJSON()、Fiber 的 c.BodyParser())会绕过你的 UseNumber() 设置。必须在中间件或 handler 开头接管原始 body,用 json.NewDecoder 重解——否则你写的逻辑根本没机会执行。










