一个诡异的前后端数据不一致问题的排查

这是我转战JAVA以来的第一篇博文,纪念一下。

背景

组织变动,转战JAVA差不多有一个月了,做了一个小需求,遇到一个诡异的问题。本文记录一下排查经过,顺便提醒自己后续开发中避免这样的坑。

问题描述

JAVA后端需要给前端返回一串数据,其中有个交易订单号,该交易订单在返回给前端后跟后端吐出的值不一致。直观地来看,最后的几个数字被0取代了。
一开始以为取错了交易订单号,然而从DEBUG的过程来看,后端的处理结果没有问题,返回了正确的结果给前端。
如下图所示:

当时也并没有纠结问题的根本原因,下意识地将交易订单号类型从List<Long>换成了List<String>返回就正常了。

发布以后觉得这里可能是个坑,于是研究了一下果然是有缘由的。

问题原因

既然将Long改为String就解决了问题,很自然地就想到是不是类型转换的过程中造成了精度丢失。但服务器返回的时候又是正确的,那么问题应该是出在浏览器端了。
于是着手验证:
浏览器终端上运行代码

1
2
3
4
var t = 1000006221004368407;
console.log(t); // 输出1000006221004368400
var tt = 100000622100436847;
console.log(tt); // 输出100000622100436850

至此已经能够确定是前端在解析的时候丢失精度了。

在网上搜索查到一段关于js整型大小的说明:

1
2
3
精度
整数(不使用小数点或指数计数法)最多为 15 位。
小数的最大位数是 17,但是浮点运算并不总是 100% 准确

问题解决了,巧合的是我们的项目里刚好id位数18位超过了js能够精确表达的最大位数。于是在将后端返回的数据JSON化渲染的过程中造成了精度丢失。
如果不是这个巧合,这个问题可能还不会被发现。
这也提示我们,后续如果有超长位数数字需要显示的时候,数据结构最好定义为字符串类型。