精度丢失问题
程序员文章站
2022-03-06 12:43:02
...
背景
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:
修改 service 层使 id 最小值大于 js 精度限制
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. 获取响应体的字符串,使用 JSONbig
将 id
转化成字符串
优点:只影响当前请求
缺点:不支持 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;}
~
~ 本文完,感谢阅读!
~
学习有趣的知识,结识有趣的朋友,塑造有趣的灵魂!
上一篇: 高效简单的云服务器登录配置