前言

前端与后端对接的途中,有时我们会遇到一些奇怪的坑,例如后端传给前端一个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返回内容就会是以字符串形式被前端接收。
后续处理起来就不用担心精度损失。

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐