JS大坑之19位数的Number型精度丢失问题详解


Posted in Javascript onApril 22, 2019

More

本项目仅供爬取体验,每次访问都会实时爬取数据,所以数据返回速度会比较慢,实际操作应该是定时爬取数据然后将数据存进数据库,数据从数据库返回从而提高数据返回效率。

但项目很基础,可以作为以上各个node模块最基础的练手使用,希望可以帮到大家 ?起源

最近在实现一个需求的时候,需要接入第三方的接口,先调用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),超过这个值就会出现精度丢失的问题。 Orz

获取正确的响应数据

由于在一开始使用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(),又会引起精度丢失的问题,这可真尴尬 Orz

如果这个接口是已方可控的,那么就可以把这个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 
// }

结语

使用node也有一段时间了,因为涉及不到大数计算,因此对于编号啊,ID啊,都是用字符串形式进行存储的,也就一直没有遇到这个问题。这一次居然碰上了,不得不说js在这一方面确实有点弱势,之后也尝试了下使用Go,python进行请求,都是能正确解析不过node使用起来还是很舒服的

以上所述是小编给大家介绍的JS大坑之19位数的Number型精度丢失问题详解整合,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!

Javascript 相关文章推荐
用JS提交参数创建form表单在FireFox中遇到的问题
Jan 16 Javascript
实例讲解JQuery中this和$(this)区别
Dec 08 Javascript
jQuery使用slideUp方法实现控制元素缓慢收起
Mar 27 Javascript
jQuery使用fadein方法实现渐出效果实例
Mar 27 Javascript
jQuery插件Validate实现自定义校验结果样式
Jan 18 Javascript
Javascript对象字面量的理解
Jun 22 Javascript
慕课网题目之js实现抽奖系统功能
Sep 19 Javascript
angular1配合gulp和bower的使用教程
Jan 19 Javascript
vue使用vue-i18n实现国际化的实现代码
Apr 08 Javascript
AngularJS实现的base64编码与解码功能示例
May 17 Javascript
vsCode安装使用教程和插件安装方法
Aug 24 Javascript
Vue.js中使用Vuex实现组件数据共享案例
Jul 31 Javascript
Vue $mount实战之实现消息弹窗组件
Apr 22 #Javascript
深入理解vue中的slot与slot-scope
Apr 22 #Javascript
浅析vue插槽和作用域插槽的理解
Apr 22 #Javascript
详解50行代码,Node爬虫练手项目
Apr 22 #Javascript
Vue匿名插槽与作用域插槽的合并和覆盖行为
Apr 22 #Javascript
详解Vue 匿名、具名和作用域插槽的使用方法
Apr 22 #Javascript
详解Node.js一行命令上传本地文件到服务器
Apr 22 #Javascript
You might like
PHP+MYSQL的文章管理系统(二)
2006/10/09 PHP
解析PHP强制转换类型及远程管理插件的安全隐患
2014/06/30 PHP
typecho插件编写教程(三):保存配置
2015/05/28 PHP
运用jquery实现table单双行不同显示并能单行选中
2009/07/25 Javascript
jQuery的强大选择器小结
2009/12/27 Javascript
javascript下数值型比较难点说明
2010/06/07 Javascript
js 获取元素下面所有li的两种方法
2014/04/14 Javascript
使用js Math.random()函数生成n到m间的随机数字
2014/10/09 Javascript
浅谈JavaScript字符串拼接
2015/06/25 Javascript
微信小程序 参数传递详解
2016/10/24 Javascript
从零学习node.js之搭建http服务器(二)
2017/02/21 Javascript
js仿淘宝商品放大预览功能
2017/03/15 Javascript
js实现瀑布流效果(自动生成新的内容)
2017/03/16 Javascript
Vue.js实现实例搜索应用功能详细代码
2017/08/24 Javascript
详解ES6中的 Set Map 数据结构学习总结
2018/11/06 Javascript
js中int和string数据类型互相转化实例
2019/01/16 Javascript
node.js微信小程序配置消息推送的实现
2019/02/13 Javascript
layui使用label标签的方法
2019/09/14 Javascript
vue 项目打包时样式及背景图片路径找不到的解决方式
2019/11/12 Javascript
[04:38]完美世界携手游戏风云打造 卡尔工作室饰品系统篇
2013/04/25 DOTA
Django异步任务之Celery的基本使用
2019/03/23 Python
Keras自定义实现带masking的meanpooling层方式
2020/06/16 Python
python利用appium实现手机APP自动化的示例
2021/01/26 Python
HTML5+lufylegend实现游戏中的卷轴
2016/02/29 HTML / CSS
意大利香水和彩妆护肤品购物网站:Ditano
2017/08/13 全球购物
业务部主管岗位职责
2014/01/29 职场文书
个性与发展自我评价
2014/02/11 职场文书
资金主管岗位职责范本
2014/03/04 职场文书
农业局学习党的群众路线教育实践活动心得体会
2014/03/07 职场文书
经营理念标语
2014/06/21 职场文书
大学生作弊检讨书
2014/09/11 职场文书
秦始皇兵马俑导游词
2015/02/02 职场文书
傲慢与偏见读书笔记
2015/06/29 职场文书
七年级作文之关于奶奶
2019/10/29 职场文书
简述python四种分词工具,盘点哪个更好用?
2021/04/13 Python
MySQL索引失效的典型案例
2021/06/05 MySQL