写点什么

精度丢失问题

作者:编程三昧
  • 2022 年 2 月 03 日
  • 本文字数:1419 字

    阅读完需:约 5 分钟

精度丢失问题

背景

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


1713166949059674112 => 1713166949059674000

为什么会丢失?

  • 存储二进制时小数点的偏移量最大为 52 位,计算机存储的为二进制,而能存储的二进制为 62 位,超出就会有舍入操作,因此 JS 中能精准表示的最大整数是 Math.pow(2, 53),十进制即 9007199254740992 大于 9007199254740992 的可能会丢失精度

  • 参考:https://zhuanlan.zhihu.com/p/100353781

  • request-promise-native 发起请求时,当options.json 不为 false 会使用 JSON.parse 解析 body


if (self._json) {  try {    response.body = JSON.parse(response.body, self._jsonReviver)  } catch (e) {    debug('invalid JSON received', self.uri.href)  }}
复制代码

最小 demo

搭建服务 API

一、搭建 Java Web Api:



    public long getId() {        return id + 1713166949059674112L;    }* 修改 controller 层添加 post 请求    @PostMapping("/greeting_create")    public Greeting createGreeting(@RequestParam(value = "name", defaultValue = "World") String name) {        return new Greeting(counter.incrementAndGet(), String.format(template, name));    }
复制代码


二、请求


  • GET 请求: curl http://localhost:8080/greeting

  • POST 请求:curl -X POST http://localhost:8080/greeting_create


{"id":1713166949059674120,"content":"Hello, World!"}
复制代码

解决方案

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

  • 优点:只影响当前请求

  • 缺点:不支持 POST 请求方式,

  • 通过 json 传参数不支持

  • 通过 form + json: false 传参数需要后端接口支持

  • GET 请求


const rp = require('request-promise-native');const jsonBigInt = require('json-bigint');
const getOptions = { 'method': 'GET', json: false, 'url': 'http://localhost:8080/greeting', };
const getRes = await rp(getOptions); console.log('get result: ', jsonBigInt.parse(getRes));
复制代码


  • POST 请求:不支持,json 被占用,一定会执行 JSON.parse


const rp = require('request-promise-native');const jsonBigInt = require('json-bigint');
const postOptions = { 'method': 'POST', 'url': 'http://localhost:8080/greeting_create', json: { name: 'test' }, }; const postRes = await rp(postOptions); console.log('post result: ', jsonBigInt.parse(postRes));
复制代码

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

  • 优点:实现简单,支持 POST

  • 缺点:影响所有的 JSON.parse() 解析


const rp = require('request-promise-native');const jsonBigInt = require('json-bigint');
async function jsonBigReplaceParse() { const oldParse = JSON.parse; JSON.parse = jsonBigInt.parse; const postOptions = { 'method': 'POST', 'url': 'http://localhost:8080/greeting_create', json: { name: 'test' }, }; const postRes = await rp(postOptions); console.log('post result: ', postRes); JSON.parse = oldParse;}
复制代码


~


~ 本文完,感谢阅读!


~


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

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

用户头像

编程三昧

关注

学习有趣的知识,塑造有趣的灵魂! 2019.08.30 加入

还未添加个人简介

评论

发布
暂无评论
精度丢失问题