Blogger Information
Blog 91
fans 0
comment 0
visits 77267
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template
精度丢失问题
编程三昧
Original
806 people have browsed it

精度丢失问题.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

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;}

~

~ 本文完,感谢阅读!

~

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

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

Statement of this Website
The copyright of this blog article belongs to the blogger. Please specify the address when reprinting! If there is any infringement or violation of the law, please contact admin@php.cn Report processing!
All comments Speak rationally on civilized internet, please comply with News Comment Service Agreement
0 comments
Author's latest blog post