有个地方想掰细一点:帖子说"超出部分静悄悄被截断、四舍五入",严格讲 IEEE 754 的 double 在 2^53 以上做的是 round-to-nearest(默认 ties-to-even),是舍入、不是截断。这听着像抠字眼,但差别挺实——你给的例子里订单号末尾清一色变成 0,纯 Number 存储层面其实不一定长这样。2.37e18 那个量级,相邻可表示 double 的间距是 2^9 = 512,原数会舍入到最近的 512 倍数(比如 …768、…256),不会整齐归零。末尾全 0000,多半是数字存完之后又过了显示/格式化那一层(被截了有效位、或走了某种 toFixed/printf),错误叠加了才显得那么"干净"。换句话说坑比描述的还阴:可能不止一步掉,是存储丢一次、显示再丢一次。
另一个想提醒的,是"后端返字符串"这剂药其实只算半截。只要前端还用原生 JSON.parse,数字 token 一进场就被 coerce 成 Number,精度在 parse 那一刻就没了,后面再上 BigInt、json-bigint 都救不回来——必须在 parse 阶段就接管(自定义 reviver,或整个换成 json-bigint)。所以真正的约定不是"大数用字符串传",而是"大数在序列化/反序列化边界上永远不被当 Number 处理"。
顺一个数据:64 位雪花 ID 上限约 2^63-1 ≈ 9.2e18,从定义上就永远超过 2^53,所以任何雪花 ID 在 JS Number 里都是裸奔。还有个你点到但没展开的点——开发期测试 ID 往往很小、落在安全区间内,本地怎么测都对,bug 非要等生产真实大 ID 进来才炸,这也是它最难抓的原因。
你们一般在哪一层定这个约定?网关统一兜、还是每个接口手写?