Nodejs中JSON.parse的这个BUG如何解决?

Nodejs中JSON.parse的这个BUG如何解决?

最近在公司用NODEJS做一个第三方应用,请求对方接口反馈的为JSON格式的数据,如下:

{"content": "Hi", "created_at": 1340863646, "type": "text", "message_id": 5758965507965321234, "from_user": "userC"}

其中message_id是19位number类型的。我用JSON.parse解析成JSON对象获取其中的信息,方法如下:

var jsonStr = '{"content": "Hi", "created_at": 1340863646, "type": "text", "message_id": 5758965507965321234, "from_user": "userC"}';
var jsonObj = JSON.parse(jsonStr);
console.log(jsonObj.message_id);//得到结果是:5758965507965321000

得到的结果的最后三位变成000了,请问如何处理?超过16位的数据解析后均会变为000;

目前用了个暂时规避的方法是,拿到json的string字符串,先把19位message_id的值两边加双引号,写的也有问题,有么有JS高手帮忙看看哈。

目前写的临时规避方案如下,是有BUG的:

//将message_id的19位数字两边加上双引号,避免JSON.PARSE时候,JS会对超过16位的数字转换错误
//JS/v8引擎都有这个BUG,如何处理?
return JSON.parse(jsonStr.toString().replace(/:\s\d{19}/g, ":\"@!#@!#$&\"").replace(/:\d{19}/g, ":\"@!#@!#$&\"").replace(/@!#@!#:\s/g,"").replace(/@!#@!#:/g,""));

14 回复

在Node.js中使用JSON.parse解析JSON字符串时,遇到超过16位的数字可能会出现精度丢失的问题。这是因为JavaScript中的数字类型(Number)是基于IEEE 754标准的64位浮点数,其最大安全整数为Number.MAX_SAFE_INTEGER,即2^53 - 1。

对于这个问题,我们可以采用以下几种解决方案:

解决方案一:将大数字作为字符串存储

最简单且有效的方法是确保这些大数字以字符串的形式存储,而不是数字形式。这样,当解析JSON字符串时,这些数字不会被当作数字处理,从而避免精度丢失。

var jsonStr = '{"content": "Hi", "created_at": 1340863646, "type": "text", "message_id": "5758965507965321234", "from_user": "userC"}';
var jsonObj = JSON.parse(jsonStr);
console.log(jsonObj.message_id); // 输出:5758965507965321234

解决方案二:使用第三方库

如果不能修改原始JSON数据,可以考虑使用一些第三方库来处理大数字。例如,json-bigint库可以帮助正确解析大数字。

首先安装该库:

npm install json-bigint

然后使用该库进行解析:

const { JSONbig } = require('json-bigint');

var jsonStr = '{"content": "Hi", "created_at": 1340863646, "type": "text", "message_id": 5758965507965321234, "from_user": "userC"}';
var jsonObj = JSONbig.parse(jsonStr);
console.log(jsonObj.message_id); // 输出:5758965507965321234

总结

在Node.js中处理大数字时,最好的做法是将它们作为字符串存储。如果无法控制数据源,可以使用如json-bigint这样的库来正确解析大数字。这不仅解决了精度丢失问题,还提高了代码的可读性和维护性。


js对超大数据不知道是怎么处理的,不像java一样,js好像对超过4个字节的数据就用科学计数法来存储的。楼主的message_id为什么不用字符类型呢。

这是是别人系统返回的,我们控制不了。

这个是正常的,涉及到js中number的最大值问题,请参看在Javascript中,最大的Number是多少?

请问对于这种直接获取到的json格式的字符串,你有没有什么好的建议哈?

有没有兄弟有写好的解决了这个错的JSON.parse()呢?

javascript 的数字类型是 64bit 浮点数,最大精度有限,您的值超出了这个范围,一共 19 位,

JS number 类型表示整数只能在 −9007199254740992 (−e53) and 9007199254740992 (e53) 这个范围内是精确的,这个只有 16 位,所以您的后3位自然就写 0 了。

e53 = 53/3 = 17.3*3 也就十进制 17 位所有的表达精度。

如果你非要使用数字类型,那么就没法解决。除非使用字符串型。

谢谢你的讲解,呵呵。可惜这个JSON字符串是对方接口返回的,我也没办法控制,所以就悲剧了。 {“content”: “Hi”, “created_at”: 1340863646, “type”: “text”, “message_id”: 5758965507965321234, “from_user”: “userC”}

JSON.parse方法的第二个参数是个回调,可以用来处理每个成员。

一个办法,在parse之前先把数字转化成字符串,要实现这个也很简单,先找到message_id的 位置,在找到:和,号的位置,在处理一下,貌似没有更好的办法了

目前用的就是这个思路。。

目前用的就是这个思路。。

在Node.js中,JSON.parse 方法本身没有bug,但JavaScript的数字类型默认只能精确表示到小数点后16位,因此对于超过16位的数字,它会自动转换为科学计数法或者四舍五入,从而导致精度丢失。

为了正确处理这种大整数,可以将 message_id 字段作为字符串而不是数字来处理。具体的做法是在发送数据时将 message_id 作为字符串发送,这样在接收端解析时就不会出现精度丢失的问题。

示例代码

假设我们有一个包含 message_id 的 JSON 字符串:

const jsonStr = '{"content": "Hi", "created_at": 1340863646, "type": "text", "message_id": "5758965507965321234", "from_user": "userC"}';

const jsonObj = JSON.parse(jsonStr);

console.log(jsonObj.message_id); // 输出: "5758965507965321234"

在这个例子中,message_id 被包裹在双引号中,所以它会被解析为一个字符串,而不是一个数字。

临时规避方案的问题

您提到的临时规避方案通过替换字符串的方式来尝试解决这个问题,但这种方法复杂且容易出错。更好的做法是确保在发送数据时,将所有可能超过16位的数字字段作为字符串处理。

总结

  • 使用字符串来表示超过16位的大整数。
  • 确保服务器端发送的数据中,这些字段已经是字符串形式。

通过这种方式,可以有效避免 JSON.parse 中的精度丢失问题。

回到顶部