JavaScript(JS)、JSON和int64

大家在前后端联合开发时经常会遇到一个问题,js不能处理服务端返回的JSON中的大整数。处理方法往往是将这个大整数字段设置为string。

为什么js不能处理大整数了?
因为之前js只有number类型来表示数字(整数+浮点数),其遵循IEEE 754规范,是一个双精度 64 位二进制格式值,其整数的最大支持2的53次方-1(2^53-1):9007199254740992。内置常量Number.MAX_SAFE_INTEGER值为9007199254740991(2^53-1),因为当赋值给Number类型变量大于此值时(比如2^53,2^53+1,……),都会被存储为2^53。顺带提一下,还有一个常量:Number.MAX_VALUE。

后来新增了BitInt这种内置类型,它提供了一种能力来表示大于 2^53 – 1 的整数。而且BigInt 可以表示任意大的整数。
可以用在一个整数字面量后面加 n 的方式定义一个 BigInt ,如:10n,或者调用函数 BigInt()(但不包含 new 运算符)并传递一个整数值或字符串值。

const theBiggestInt = 9007199254740991n;
const alsoHuge = BigInt(9007199254740991);
// 9007199254740991n
const hugeString = BigInt("9007199254740991");
// 9007199254740991n
const hugeHex = BigInt("0x1fffffffffffff");
// 9007199254740991n
const hugeBin = BigInt("0b11111111111111111111111111111111111111111111111111111");
// 9007199254740991n

 

那么又有新问题了,既然js支持大整数,那么为什么服务端不能返回大整数了?
因为我们服务端返回数据设定Content-Type: application/json时,我们告诉客户端这是一段json,而根据json规范的定义,其只支持js的number类型,而不支持BitInt类型,所以当服务端返回的json包含了一个大于Number.MAX_SAFE_INTEGER的整数时(其实这个时候严格来说服务端没有遵循json规范),客户端不能识别是正常的现象(按照上文提到的,会被转换成2^53),是符合json的规范的行为。那所以web客户端这边没有把服务端返回的大整数转换成BitInt类型是源于遵循JSON规范。既然web客户端不支持大于2^53-1的整数,那么服务端就应该避免返回这些数据,所以如果某个字段是int64类型,那么为了安全,建议将int64转换成string类型返回,服务端接收web客户端参数时也一样。

当然我们期待json规范也能更新(到时出现一个Content-Type: application/json2,哈哈),能够原生支持BitInt类型,然后内置的JSON对象的parse()和stringify()两个方法也升级支持BitInt类型。这样我们开发者就可以安全方便的在前后端之间传输int64类型数据了。

References:

https://zh.wikipedia.org/wiki/雙精度浮點數

https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Number

https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/BigInt

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注

*