雪花 ID 与 JSON 编码
问题
业务表主键是 19 位雪花 ID(如 1761100000000000001),超出 JS 安全整数范围(±9007199254740991)。前端 JSON.parse 会把它当成 float64, 末几位精度丢失。
Java 侧用 BigNumberSerializer 按值把超长 ID 序列化成字符串解决。本项目等价物是 pkg/jsonx。
解法:全局 codec 按值判断
pkg/jsonx 接管 gin 的 JSON codec, 按值判断:
- 出参:int64 超出 JS 安全整数范围 → 自动转字符串。
- 入参:同时认数字与字符串(出参既然变字符串,前端回传详情时送来的是字符串)。
// cmd/standalone/main.go
jsonx.Init() // 必须在首个 c.JSON / 参数绑定之前VO/BO/entity 的 ID 字段一律用裸 int64
两条禁止
- 不要加
,stringtag。加,string反而会 拒收数字形态。 - 不要为 ID 套自定义类型。
pkg/jsonx 已按值兜住,加 ,string 是多余且有害的。
为什么按值而非按字段
同一个 JSON key 的值域可以横跨安全线两侧。典型:sys_menu / sys_dept 的 parentId,根节点是 0(安全范围内,前端 form.parentId !== 0 是严格比较),子节点是 19 位雪花值(超范围,要转字符串)。若按字段挂自定义类型恒转字符串,根节点的 0 也变 "0","0" !== 0 恒 true,前端逻辑崩。
故必须按值判断:0 出成数字 0,1761... 出成字符串 "1761..."。
缓存与自定义 MarshalJSON 也走 jsonx
- 缓存序列化(
cache.Put)统一走pkg/jsonx,保持 int64 字符串契约。 - 任何自定义
MarshalJSON(如pkg/tree的扁平 JSON)内部用jsonx.Marshal而非encoding/json,否则会绕过编码器让 id 形态不一致。
详见 pkg 参考 / jsonx · snowflake · constant · enum。
雪花 ID 发号
各业务表主键都是
bigint not null无auto_increment,插入前必须由应用层发号(GORM 无等价机制):goadd.ID = snowflake.Next()多进程部署每个进程必须配不同
workerId,否则撞号。已分配:auth=1、system=2、resource=3、standalone=0。同模块多副本须各自覆盖。epoch=1577836800000(2020-01-01 UTC),上线后不可再改(否则新旧 ID 大小关系错乱)。时钟回拨不 panic 而是等追平(旁路写入如登录日志不该打挂进程)。