- A+
项目开发中前后端数据交互常会使用id作为主键索引,通常id数值都不大,使用number类型就可以表示处理,但对于一些分布式id或其他情况,id数值太大且超过了JS的最大处理数(Math.pow(2, 53) = 9007199254740992)时就会存在精度问题:Math.pow(2, 53) + 1 = 9007199254740992;
实际例子:
当后端返回了这样一个id数值的数据,可以看到此数值已经超过了JS的最大处理数,丢失了精度,前端此时拿到的id值是错误的,此时涉及id的前后端数据交互,前端传输的参数id为1528669910682108000,后端无法根据此id找到对应的数据或者找出了其他数据导致异常
可以通过浏览器控制台Network的Preview和Response查看差异。Response中是原始响应数据,这里的id是正确的为1528669910682107904。而Preview中是浏览器接收到Response,通过JS转化为JavaScript对象形式,并格式化层级结构,以便查看,此时经过了JS处理,id数值精度丢失,看到的就是1528669910682108000这个错误id,前端请求后接收到的id也是这个错误id。
解决办法一:通过后端解决,把id转化为字符串类型返回
这样获取到的id就是正确的id了,但是后端有数据类型严格定义,不愿意改的话,那就靠我们前端来解决(方法二)
解决办法二:JavaScript新增的基础数据类型bigint就可以解决此类问题
将id转化为bigint类型,使用到json-bigint插件处理json数据中的这类数值
npm install -S json-bigint 底层依赖于bignumber.js
然后在请求方法文件中import JSONBigInt from 'json-bigint';
在请求函数中添加这一段转化代码,此时可以console.log出接收到的id为
其他地方不需要改动,这个时候前后端数据交互时id参数传输的时候会自动转化为字符串类型传输{id: "1528669910682107904"}
但是新问题又来了,现在是vue+element-ui项目,table表格绑定row-key="id",此时会报错
解决办法一:写一个全局转化函数
function transId(row) { return row.id.toString(); }
然后在使用到id的地方调用此函数,转化为字符串类型去处理eg: (:row-key="transId")
解决办法二:在之前import JSONBigInt的地方添加代码:
const JSONBigIntStr = JSONBigInt({ storeAsString: true });
自动将BigNumber转化为字符串类型,然后修改转化代码
这样console.log出id就不为BigNumber类型的了,而是字符串类型,且id和后台的id能够对应得上