JSON 大整数 · BigInt · API 设计

JSON 大整数为什么会丢失精度

订单号、雪花 ID、数据库 bigint 和高精度金额经常以 JSON 数字返回,但 JavaScript Number 只能精确表示有限范围内的整数。理解精度丢失发生在哪一步,才能避免“接口返回正确、前端显示却变了”的问题。

约 9 分钟更新于 2026-07-20 示例不包含真实业务数据
  • JavaScript 安全整数范围是 -(2^53-1) 到 2^53-1,即 Number.MAX_SAFE_INTEGER。
  • 大整数一旦被 JSON.parse 转成 Number,精度可能已经丢失,之后再转 BigInt 无法恢复原值。
  • 跨语言 API 中的订单号、用户 ID 和雪花 ID,最稳妥的方式通常是按字符串传输。

精度为什么会丢失

JSON 标准只定义 number,没有规定具体使用 32 位、64 位整数还是双精度浮点数。Java、Go、数据库和 JavaScript 对数字的表示方式不同,同一段 JSON 在不同语言中可能得到不同的精度。

JavaScript 的 Number 使用 IEEE 754 双精度浮点数。超过 9007199254740991 后,并非每个整数都能被单独表示,相邻的两个大整数可能映射到同一个 Number。此时比较、显示或重新序列化都可能出现错误。

超过安全整数范围
Number.MAX_SAFE_INTEGER
// 9007199254740991

9007199254740992 === 9007199254740993
// true

为什么 JSON.parse 之后再转 BigInt 已经太晚

JSON.parse 会先把数字文本转换成 Number。如果原始值超出安全整数范围,这一步就可能发生舍入。随后执行 BigInt(parsed.id),得到的是舍入后的数字,而不是响应中的原始字符。

如果 API 无法调整,可以在解析前使用能够保留大整数原始文本的专用解析库;但这会增加前端复杂度。能够控制接口时,优先让服务端把标识符和高精度值输出为字符串。

存在风险的 API 响应
{
  "orderId": 9223372036854775807,
  "amount": 9999999999999999
}
更稳妥的传输方式
{
  "orderId": "9223372036854775807",
  "amount": "9999999999999999",
  "amountScale": 2
}

不同类型数据的解决方案

标识符通常不参与数学运算,因此应按字符串处理。需要整数运算时,可在确认原始文本未丢失的前提下转换为 BigInt。金额和小数更适合使用最小货币单位整数,或由 Decimal 类型和字符串共同表示。

数据类型推荐传输方式前端处理
订单号、用户 ID、雪花 ID字符串保持字符串,不做 Number 转换
超大整数计数字符串需要计算时转换为 BigInt
金额最小单位整数或十进制字符串使用 Decimal 库或整数运算
普通页码、数量JSON number确认值在安全整数范围内

API 设计与排查清单

前后端应在接口文档中明确字段是数值还是标识符,不要仅根据数据库列类型决定 JSON 类型。数据库 bigint 用于保存 ID,并不意味着前端也应该把它当作可计算的 number。

排查精度问题时,应对比浏览器 Network 面板中的原始响应文本、JSON.parse 后的值以及界面最终显示值。如果原始响应已经错误,应检查服务端序列化;如果原始响应正确但解析后变化,应调整字段类型或解析方式。

  • 确认原始响应中的数字是否已经发生变化。
  • 检查字段是否超过 Number.MAX_SAFE_INTEGER。
  • 标识符统一使用字符串,并在接口文档中固定类型。
  • 避免把字符串 ID 经过 Number、parseInt 或一元加号转换。
  • 为最大值、边界值和跨语言序列化增加自动化测试。

JSON 格式化工具能帮助什么,不能替代什么

格式化工具适合查看原始层级、搜索字段、比较文本和发现可疑的大整数。树形预览可以提高排查效率,但如果底层解析器已经把数字转换为 Number,预览结果也可能受到精度限制。

因此,处理金融级金额、数据库 bigint 或业务 ID 时,应以接口原始文本和服务端约定为准。格式化工具是诊断入口,不能替代正确的数据类型设计。

边看边操作

使用在线 JSON 工具检查大整数

格式化接口响应并搜索可疑字段,同时保留原始响应用于精度对比。

打开工具

FAQ

常见问题

JSON 本身支持 BigInt 吗?

JSON 标准没有 BigInt 类型,只有 number。不同语言可以用自己的大整数类型解析 number,但跨语言传输时通常建议使用字符串。

订单号为什么不应该使用 Number?

订单号是标识符,不需要数学运算,而且可能超过 JavaScript 安全整数范围。使用字符串既能保留前导零,也能避免精度丢失。

金额使用字符串会不会不方便计算?

可以使用十进制字符串配合 Decimal 库,或传输最小货币单位的整数。直接使用浮点数可能产生二进制小数误差。