前言
前端与后端对接的途中,有时我们会遇到一些奇怪的坑,例如后端传给前端一个Long类型的数据(可能是某张表的id或是某个随机值),但是前端接收后,数据竟然发生了微妙的变化,这背后的底层原理,就是JS语言number
数据类型的精度丢失。
原因分析
在提及如何解决之前,我们得先知道前端JS具体是如何丢失精度的。
前端存储数值的类型叫做number
,它的数据范围很奇怪(相对于其他语言),安全整数范围是 -(2^53 - 1) 到 2^53 - 1
,这就导致它的范围大于后端(例如Java)的int
,但是小于后端的Long
。
而一旦我们传给前端一个超过其范围的数字,JS就会以浮动数(floating point)
的方式存储它,其后果就是我们往往发现Long类型的数据,最后一位可能发生变化.
解决思路
常见误区
1.接受异步返回值并以BigInt
存储
很容易想到的解决思路,就是获取到异步请求返回值后以BigInt
存储,由于BigInt的上限理论上可以无限大,因而不会造成精度损失。
但是这种方式忽略了一个事实,就是我们通过异步请求获取到返回值时,后端的Long
已经自动转换成了number
类型。即使我们继续将其转化为BigInt,已经造成的精度丢失也无法逆转。
而且,即使我们使用的是TS,定义泛型也依旧不能阻止数值
被转换成number
.
2.接受异步返回值并以String
存储
本质和上面一样,如果后端的json
数据是数值类型的,那么异步返回获取到的数据就会自动转换number
类型,即使后续转为string
也无济于事。
正确思路
后端将Long
类型数据以String
方式序列化,具体实现通常需要配置对应语言框架的序列化器,以Java的SpringBoot项目为例(其默认序列化器为Jackson),其配置方式如下:
@JsonSerialize(using = LongToStringSerializer.class)
private Long myLongField;
这样我们后端发送的json
返回内容就会是以字符串形式被前端接收。
后续处理起来就不用担心精度损失。