一、问题背景
雪花算法生成的id经过浏览器后id后几位全部变成"0000",导致列表展示后进入详情无法查询详情。
经dubbo服务调用,返回正常的id,经网关后查询日志也返回正常id,经Postmain调用也返回正常的id,经页面点击查询后查看列表信息,经谷歌浏览器开发工具Network查看,返回数据id的结尾已经变成"0000";
三、问题原因
Java中Long的取值范围为-9223372036854775808到9223372036854775807(即-2^64“ 到”2^64-1)
而JavaScript中的Number取值范围为-9007199254740992 到9007199254740991 (即-2^53 到2^53-1)
四、解决方案
在传的时候把Long转换成String类型
使用spring的Json解析器时使用@JsonSerialize(using = ToStringSerializer.class) 注解
@JsonSerialize(using = ToStringSerializer.class)
private Long id;
五、 延伸探究
为什么avaScript中的Number取值范围是-2^53 到2^53-1?
IEEE 754规定了四种表示浮点数值的方式:单精确度(32位)、双精确度(64位)、延伸单精确度(43比特以上,很少使用)与延伸双精确度(79比特以上,通常以80位实现)。
Number类型使用的便是其中的双精确度(64位)数据结构如下
Number类型的51-62位为指数位,63位为符号位,所以取值范围是-2^53 到2^53-1
复制来对 Number类型 相对官方的解释.
ECMAScript 中最有意思的数据类型或许就是 Number 了。Number 类型使用IEEE 754 格式表示整数和浮点值(在某些语言中也叫双精度值)。 ---红宝书
在 JavaScript 中, Number 是一种 定义为 64位双精度浮点型(double-precision 64-bit floating point format) (IEEE 754)的数字数据类型。 ---MDN
Number 类型使用IEEE 754 格式。
IEEE 754 格式
IEEE 754规定了四种表示浮点数值的方式:单精确度(32位)、双精确度(64位)、延伸单精确度(43比特以上,很少使用)与延伸双精确度(79比特以上,通常以80位实现)。
Number类型使用的便是其中的双精确度(64位)。
这张图就把结构说清了。
举个例子
- 十进制数值:10.25
- 转化为二进制 => 1010.01
- 规格化 => 1.01001 * 2^3
- 存储: 01001放在尾数位置,3放在指数位。指数位有11位,则移码是1023+3,为100...0010,移码参考这个IEEE754表示浮点数。整个表示为这样:
考虑能表示的最大值,就要看:
在固定位数时候所能表示的最大值。
指数位 移码最大值为11位1,原码最大值为10位1(原码最高位表示符号位),则y最大为1023,x最大表示52位1。即1.1111...1乘以 2^1023,即2^1023*(2-2^-52) 这个值也就是 Number.MAX_VALUE 的大小
最大安全数
什么叫最大安全整数?指的也就是这个常量Number.MAX_SAFE_INTEGER
现在考虑,我们看两个数2^53与2^53+1。
- 2^53 我们尝试把它表示成二进制:1 53个0 ,规格化 1.0...00 * 2^53
- 那2^53+1呢?我们尝试把它表示成二进制:1 52个0 1 ,标准化 1.0...01 * 2^53
问题来了,尾数都有53位,但只要52个空! 它的处理办法是 忽略第53位 ,因此这两个数在计算机中表示的结果一样!
2**53===2**53+1 //true 复制代码