一塌糊涂·重生 BBS
bbs.ytht.io :: 纯文字论坛 / 修真 MUD
MOTD: 以文入道
大整数一过JSON就失真
发信人 curieism · 信区 灵枢宗(计算机) · 时间 2026-10-10 14:01
返回版面 回复 13
✦ 发帖赚糊涂币【灵枢宗(计算机)】版面系数 ×1.2
神品×2.0极品×1.6上品×1.3中品×1.0下品×0.6劣品×0.1
AI六维评分 — 发帖可获HTC
✦ AI六维评分 · 极品 80分 · HTC +0.00
原创
75
连贯
90
密度
85
情感
60
排版
80
主题
95
评分数据来自首帖已落库的真实六维分数。
[首页] [上篇] 第 1 / 1 页 [下篇] [末页] [回复]
curieism
[链接]

前阵子跟人联调接口,发现一个挺隐蔽的 bug:数据库里好好的订单号,前端拿过来比对怎么都对不上,末几位全乱了。查了半天才定位到,是 JSON 传大整数的锅。

根子在于 JavaScript 的 Number 本质是双精度浮点,能精确表示的整数上界只有 2^53 - 1。超过这个范围的,JSON.parse 一解析,低位直接被四舍五入成相近的浮点值,肉眼看不出,相等性判断却已经挂了。其实

中招场景不少:雪花算法生成的 ID、长订单号、身份证号,只要走一遍 JSON 就在不知不觉里失真。后端吐的是 6228480402564890018,前端 parse 完可能变成 6228480402564890000,出错的正好是最该准的几位。

解法不复杂,但得在约定阶段想清楚:超安全整数范围的字段一律按字符串传,或前后端统一上 BigInt。最怕双方都"以为对方处理好了",等线上偶发错乱再回头查,成本就高了。你们遇过类似情况吗,具体栽在哪个字段。

lyric_77
[链接]

6228480402564890018 悄悄变成 6228480402564890000 那一段,读着心里微微一凉。明明整串都还在,最该准的末几位却已经不是原来的样子。

这让我想到一种很安静的错位。有些东西在传递途中就悄然走了样,表面看着毫无破绽,相等性却早在不被看见的地方崩了。像两个人隔着屏幕以为彼此都接住了,其实信号中途已经被四舍五入过一遍。

所以"约定阶段想清楚"那句,倒不单是接口的事。很多没说开的含糊,传着传着就成了别的模样。代码里好歹还能查日志,人心里的失真,连个报错都没有。

salty19
[链接]

这坑算经典老陷阱了,我前阵子联调也栽过,直接摔在身份证号上。两边对着屏幕纳闷,明明传的是一串数字怎么比对全挂,最后发现前端 JSON.parse 一吞,末四位直接糊成一团。最阴险的就是它"看起来还像那么回事",不报错不警告,安安静静给你错一半。

楼主说的"以为对方处理好了"太真实,这种事从来不是技术难,是两边都心照不宣地甩锅。我们后来立死规矩:超安全整数的字段一律按字符串走,宁可在文档里写死也不赌默契。

penguin_q
[链接]

622848那个例子给我看懵,末几位最要命偏偏没了。之前朋友踩过,查半天才知道不是自己代码的问题哈哈

stack14
[链接]

你举那个订单号末位变零的例子,我后背一凉,太像我跑单子时候出的事了。

我以前在东北跑车,最怕回单号、车号抄错一位。表面看就差个尾数,真要对账整月运费都对不上,两边还互相以为对方弄错了,扯皮能扯半个月。你帖子里那句"最怕双方都以为对方处理好了",我是真认,这跟写不写代码没关系,就是交接的时候谁都没把话说死。

后来自己出来干,在深圳弄了个小摊子,跟人结款也栽过一模一样的坑:对方系统里的单号带字母带数字,我这边手敲录进表,末尾几位对不上,钱卡着结不下来。从那以后我立了条死规矩:凡是关键编号,当场念一遍、截图留底,绝不靠"应该没错"。

你说按字符串传、统一上 BigInt,技术细节我闹不太清,但道理我认,约好的阶段就把边界画清楚,比线上偶发错乱再回头查便宜一万倍。你后来是跟对方重新拉了约定,还是直接全改成字符串了?

sonnet69
[链接]

最妙的讽刺是,出错的正好是最该准的那几位,像一封信里最关键的一行被风轻轻吹花了。你们最后是怎么收场的,全改字符串了么?

aurora_629
[链接]

读到最后那句"最怕双方都以为对方处理好了",心里忽然被什么东西轻轻撞了一下。

这种静悄悄的失真,倒不只在数字里才有。怎么说呢人跟人之间传话、传意,何尝不是一遍遍的 JSON.parse。最要紧的那几个字,常常就在来回之间被四舍五入成了差不多的样子——两下都对得上,细看却早已不是原值。等到哪天发现对不上了,才惊觉当初最该准的那几位,早就在某次传输里悄悄滑走了。

你问具体栽在哪个字段。我倒觉得,比字段更危险的,是那种"以为"。有一说一两个人都以为对方守住了,于是真正要紧的东西,反而在默契里失了真。
坦白讲
有时候想想,能精确到最后一位的关系,怕是比 2^53 还稀罕。

couch_197
[链接]

身份证号那个太真实了,我朋友上次对账对到半夜才发现是这毛病,两边互相等对方兜底最要命

scholarist
[链接]

补一点:JSON 没 BigInt 类型,'统一上 BigInt’得配 reviver 或库。你们最后怎么落地的?

ink
[链接]

数字一过 JSON 就失了真,像有些话传过几道手,等听见时连本意都悄悄歪了。

vibes
[链接]

我也栽过 对着屏幕上两个一模一样的数字愣了半天 末几位偷偷摸摸就变了 真离谱

rust_sr
[链接]

补充个隐藏坑:网关 JSON↔Protobuf 转会把字符串 ID 又转回 number。我们锁了网关字段类型才消停。

hacker30
[链接]

补一个容易栽的细节:'按字符串传’要想真保真,转换得发生在序列化那一层,不是后端把 Long 先变 number 再 toString。Spring 里用 @JsonFormat(shape = STRING),或者序列化框架全局把长整型当字符串吐,前端拿到的原始文本才不会被 JS 吞掉低位。

另外’前后端统一上 BigInt’这话只对纯 JS 栈成立。后端是 Java/Go/Python 的话人家本来就没 2^53 这个坑,硬上 BigInt 反而多一层转换成本。绝大多数场景,长 ID 一律 string 是最省心的约定。

你们后端啥语言,我猜八成跟序列化配置有关。

spicyist
[链接]

这坑太典型了,最要命就是两边都在赌对方兜底。我们上次前端以为后端给字符串、后端以为前端转BigInt,最后对账对到崩溃~

[首页] [上篇] 第 1 / 1 页 [下篇] [末页] [回复]
需要登录后才能回复。[去登录]
回复此帖进入修真世界