精度丢失问题.001

背景

  • BFF Client 使用的 npm 包 request-promise-native 请求微服务接口返回 ID 精度丢失

1713166949059674112 => 1713166949059674000

为什么会丢失?

  • 存储二进制时小数点的偏移量最大为52位,计算机存储的为二进制,而能存储的二进制为62位,超出就会有舍入操作,因此 JS 中能精准表示的最大整数是 Math.pow(2, 53),十进制即9007199254740992大于 9007199254740992 的可能会丢失精度
  • request-promise-native 发起请求时,当options.json 不为 false 会使用 JSON.parse 解析 body
  1. if (self._json) {
  2. try {
  3. response.body = JSON.parse(response.body, self._jsonReviver)
  4. } catch (e) {
  5. debug('invalid JSON received', self.uri.href)
  6. }
  7. }

最小 demo

搭建服务 API

一、搭建 Java Web Api:

  1. public long getId() {
  2. return id + 1713166949059674112L;
  3. }
  4. * 修改 controller 层添加 post 请求
  5. @PostMapping("/greeting_create")
  6. public Greeting createGreeting(@RequestParam(value = "name", defaultValue = "World") String name) {
  7. return new Greeting(counter.incrementAndGet(), String.format(template, name));
  8. }

二、请求

  • GET 请求: curl http://localhost:8080/greeting
  • POST 请求:curl -X POST http://localhost:8080/greeting_create
  1. {"id":1713166949059674120,"content":"Hello, World!"}

解决方案

1. 获取响应体的字符串,使用 JSONbigid 转化成字符串

  • 优点:只影响当前请求
  • 缺点:不支持 POST 请求方式,
    • 通过 json 传参数不支持
    • 通过 form + json: false 传参数需要后端接口支持
  • GET 请求
  1. const rp = require('request-promise-native');
  2. const jsonBigInt = require('json-bigint');
  3. const getOptions = {
  4. 'method': 'GET',
  5. json: false,
  6. 'url': 'http://localhost:8080/greeting',
  7. };
  8. const getRes = await rp(getOptions);
  9. console.log('get result: ', jsonBigInt.parse(getRes));
  • POST 请求:不支持,json 被占用,一定会执行 JSON.parse
  1. const rp = require('request-promise-native');
  2. const jsonBigInt = require('json-bigint');
  3. const postOptions = {
  4. 'method': 'POST',
  5. 'url': 'http://localhost:8080/greeting_create',
  6. json: { name: 'test' },
  7. };
  8. const postRes = await rp(postOptions);
  9. console.log('post result: ', jsonBigInt.parse(postRes));

2. 使用 JSONbig.parse() 替换 JSON.parse()

  • 优点:实现简单,支持 POST
  • 缺点:影响所有的 JSON.parse() 解析
  1. const rp = require('request-promise-native');
  2. const jsonBigInt = require('json-bigint');
  3. async function jsonBigReplaceParse() {
  4. const oldParse = JSON.parse;
  5. JSON.parse = jsonBigInt.parse;
  6. const postOptions = {
  7. 'method': 'POST',
  8. 'url': 'http://localhost:8080/greeting_create',
  9. json: { name: 'test' },
  10. };
  11. const postRes = await rp(postOptions);
  12. console.log('post result: ', postRes);
  13. JSON.parse = oldParse;
  14. }

~

~ 本文完,感谢阅读!

~

学习有趣的知识,结识有趣的朋友,塑造有趣的灵魂!

大家好,我是〖编程三昧〗的作者 隐逸王,我的公众号是『编程三昧』,欢迎关注,希望大家多多指教!

更多相关文章

  1. Android中shape的使用大全
  2. Android最佳实践之Notification、下拉刷新、内存及性能建议等
  3. Android(安卓)控件阴影实现
  4. Android(安卓)- Rerofit-RxJava(转载)
  5. android Toolbar的使用结合状态栏与返回键
  6. Android(安卓)使用WebView
  7. 谷歌开发工具Android(安卓)Studio安装使用图文教程
  8. 【Android】 使用ADT16出现ImageView Warning:Missing content D
  9. 考虑Android向后兼容的几条黄金法则

随机推荐

  1. 基于MySQL查询的Laravel路由
  2. 【实战】如何通过html+css+mysql+php来快
  3. 在使用PHP编程时,使用存储过程还是硬编码S
  4. 如何在php / mysql中使用事务
  5. Zend Studio-8.0.0中文汉化教程及入门教
  6. 使用php codeigniter进行Mysql数据库同步
  7. 填充PHP数组:首先检查索引?
  8. 整理一些Thinkphp开发的实用的一些系统源
  9. Win7安装php7 + apache2.4,成功启动
  10. 速率结构的数据库/算法