前端向服务端请求某个订单数据,其中订单号 18 位,在 数据库 中以数字的形式保存,服务端查询数据库后向前端返回如下数据:
{ code: 0, message: 'success', data: { uid: 10001, productId: 100003, orderId: 179828993786548789 }
前端调用接口后,通过 http 传输的数据并不是 JSON,而是 JSON 字符串:
"{"code":0,"message":"success","data":{"uid":10001,"productId":100003,"orde rId":179828993786548789}}"
由于在各大 HTTP 请求库的内部,实现了对application/json 等各种类型返回数据的格式化,也就是调用JSON.parse来对请求过来的数据进行处理,因此,前端通过这些调用获取到的数据已经是被格式化了,得到了如下数据:
{ code: 0, message: 'success', data: { uid: 10001, productId: 100003, orderId: 179828993786548800 }
很明显可以看到,orderId变化了,这是因为js的number类型有个最大值(安全值)。即2的53次方减1,为9007199254740991。如果超过这个值,那么js会出现不精确的问题。这个值为16位。
其实最简单的解决方案,也是大家一下子就能想到的,就是让服务端把订单号以字符串的形式返回回来。这是最简单最便捷的解决方式。
我们这里仅针对这个问题来解决问题,从自身出发寻找解决方案。
无论是 fetch 还是 axios 等各种 HTTP 库,都提供了类似于 formatResponseData 的方法,可以自己传入格式化的方法而不是使用默认的 JSON.parse 。问题的解决入口就在于此。
fetch
axios
formatResponseData
JSON.parse
在 formatResponseData 中,找到对应的字段,并将其值改为字符串,再使用 JSON.parse 方法来格式化。
为什么不推荐呢?不通用,仅针对当前业务解决问题。
使用 json-bigint 处理返回值。
json-bigint 提供了几个示例,为了彻底解决,将大数转换为字符串是比较保险的方案,因此推荐下面这个方案:
json-bigint
执行内容:
var JSONbigString = require('json-bigint')({"storeAsString": true});