JS踩坑实战之19位数Number型精度丢失问题详析

作者:weixin_52485890 时间:2024-04-10 10:44:23 

前言

这篇文章主要介绍了JS大坑之19位数的Number型精度丢失问题,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,有兴趣的朋友们可以一起来学习探讨。

最近在实现一个需求的时候,需要接入第三方的接口,先调用A接口,A接口返回的数据里,有一个taskId,然后再使用这个taskId请求B接口,获取最终需要的数据。

后端使用的是node,因此最开始使用的是request-promise这个包请求第三方接口,然而在获取A接口返回的taskId之后,调用B接口之后,B接口的响应居然是系统错误!简易代码如下:

const rp = require('request-promise')
const { taskId } = await rp('https://xxx.com/A')
const options = {
  method: 'POST',
  uri: 'https://xxx.com/B',
  body: {
   taskId
 },
  json: true
}
const result = await rp(options)
// {
//  "errorcode": "40001",
//  "message": "系统错误",
//  "status": "failed"
// }

接着我使用postman请求A接口,获取新的taskId,再用新的taskId请求B接口,结果却是正常的!

我在反复检查代码,确认请求的参数都是正常的格式之后,一时陷入了无尽的沉思之中……

发现 

在做了几次尝试之后,我发现使用node请求得到的taskId最后两位数都是0,即1152921504735848700,而使用postman获取的taskId,则是比较正常的是1152921504735848759,接着我在node控制台做如下操作:

JS踩坑实战之19位数Number型精度丢失问题详析

就是这么一瞬间,顿悟了。A接口里的taskId是个19位数字,而request-promise在将数据解析成json时,导致这个19位的数字丢失了精度,查了下资料,发现js的number类型有个最大安全值,即2的53次方(9007199254740992),超过这个值就会出现精度丢失的问题。

获取正确的响应数据 

由于在一开始使用request-promise包,因此获取的taskId是丢失了精度了,因此改用了node原生的http模块发送请求。

const req = https.request('https://xxx.com/A', (res) => {
 res.on('data', (chunk) => {
 // 由于这里获取到的响应数据是JSON字符串,因此19位的数字只是字符串的一部分,这时获取到的taskId就是正确的数字
  console.log(`BODY: ${chunk}`);
 });
 res.on('end', () => {
  console.log('No more data in response.');
 })
})

虽然获取到了正常的响应数据,但是这是个JSON字符串,接下来还要把这个字符串解析成JSON,但是用JSON.parse(),又会引起精度丢失的问题,这可真尴尬 ……

如果这个接口是已方可控的,那么就可以把这个19位数的number转成字符串,这样在解析的时候就不会出错了,但是由于是第三方接口,因此没法改变。那么最快的解决方案,就是换种编程语言请求啊。

最后的解决

好吧,最后还是用了node,不过我用了比较硬核的方案实现,先在获取的JSON字符串中,找到这个19位的数字,然后为它加上引号,这样再用JSON.parse()解析的时候,就能保持正常的数值,这样接下的流程就自然通了,代码如下:

let result = '{"taskId":1152921504735848759,"status":"CREATED","progress":0.0,"success":true}'
// JSON.parse(result) 不为19位数补上双引号,直接parse时,精度丢失,结果如下:
// {
//  taskId: 1152921504735848700,
//  status: 'CREATED',
//  progress: 0,
//  success: true
// }
const taskId = result.match(/[0-9]{19}/)[0] // 正则获取19位数字的值
result = result.replace(taskId,`"${taskId}"`) // 补上双引号
const data = JSON.parse(result)
// {
//  taskId: '1152921504735848759', // 解析出来之后是字符串,因此没有丢失精度
//  status: 'CREATED',
//  progress: 0,
//  success: true
// }

来源:https://blog.csdn.net/weixin_52485890/article/details/124626042

标签:js,number类型
0
投稿

猜你喜欢

  • pyftplib中文乱码问题解决方案

    2023-11-10 11:34:07
  • 数组保存为txt, npy, csv 文件, 数组遍历enumerate的方法

    2021-05-05 05:36:39
  • 使用ASP遍历并列表显示目录文件

    2009-11-08 18:32:00
  • 一次Mysql update sql不当引起的生产故障记录

    2024-01-21 09:09:22
  • 引用其它js时如何同时处理多个window.onload事件

    2024-04-16 10:31:47
  • 使用python进行图片的文字识别详细代码

    2021-06-27 07:01:06
  • 分析SQL语句性能3种方法分享

    2024-01-14 23:15:57
  • python提取页面内url列表的方法

    2022-12-26 15:29:27
  • 设置密码保护的SqlServer数据库备份文件与恢复文件的方法

    2011-11-03 16:55:30
  • Go语言学习之指针的用法详解

    2024-02-12 06:56:10
  • PHP实现的redis主从数据库状态检测功能示例

    2023-09-08 01:36:38
  • 浅析Windows 嵌入python解释器的过程

    2023-01-26 11:43:28
  • 使用Python画了一棵圣诞树的实例代码

    2022-06-18 23:55:04
  • MySQL实现分词搜索(FULLTEXT)的方法

    2024-01-22 17:47:40
  • 解决pytorch中的kl divergence计算问题

    2023-11-12 11:02:00
  • [译]2009年海外Web设计风潮(上)

    2009-01-23 09:21:00
  • Python 敏感词过滤的实现示例

    2021-07-04 12:17:28
  • asp如何编写sql语句来查询|搜索数据记录

    2008-10-09 12:35:00
  • 如何创建CSS的对象,获取合适的粒度

    2010-07-09 13:10:00
  • python计算无向图节点度的实例代码

    2022-05-24 22:42:49
  • asp之家 网络编程 m.aspxhome.com