一噩咪、問題的發(fā)現(xiàn)與描述
在處理一組第三方服務器返回的數(shù)據(jù)時顾彰,有一串訂單號始終在最后幾位有誤差,一開始以為是接口的問題胃碾,但通過抓取請求發(fā)現(xiàn)接收到的訂單號是正確的涨享,那原因就只能出現(xiàn)在解析數(shù)據(jù)的時候了。 問了度娘后發(fā)現(xiàn)仆百,原來js中的數(shù)字厕隧,大于 9007199254740992 的可能會丟失精度,
具體詳見:https://blog.csdn.net/leaf_0303/article/details/79194496
原因詳見:https://www.cnblogs.com/snandy/p/4943138.html
感謝以上大神
二俄周、解決問題的方案分析
如果是自己的服務器吁讨,或者能與接口開發(fā)者溝通的情況下,傳個字符串來代替數(shù)字便能解決問題峦朗,但麻煩的是這次接口是第三方建丧,而且在一串json字符串里,使用js常規(guī)的JSON.parse解析就是不行波势,只能考慮自己解析翎朱。
三、解決方案
考慮到通用性尺铣,就封裝了一個方法拴曲。
1、舉例子
舉例一串json的字符串:
var testString = '{"a":{"b":{"n":[{"a":"138476506","ad":"us","se":"測",' +
'"e":"0","r":"0.0","s":"1","t":"2","c":"0","id1":352677239567885445,' +
'"id2":472667239127885446}]},"q":"52"}}';
var data2 = JSON.parse(testString);
console.log(data2);
打上斷點可以清楚的看到凛忿,解析出來的對象data2的id1澈灼、id2,最后一位都被截為0了
2店溢、基本思路
基于上述例子蕉汪,基本的思路是在json字符串中找到id1和id2,將id1和id2的取值替換為字符串逞怨。
步驟1、用JSON.parse方法先解析出數(shù)據(jù)福澡,按數(shù)據(jù)的結構分對象叠赦、數(shù)組兩種方式遍歷檢查每一組鍵值對,如果有發(fā)現(xiàn)是數(shù)字類型且大于9007199254740992的革砸,記錄下來除秀。
步驟2、將原字符串中的 數(shù)字值替換為字符串值算利,以例子說明就是找到字符串
'"id1":352677239567885445'
//替換為->
'"id1":"352677239567885445"'
替換的過程又取巧拆成了兩步
//1册踩、先加左邊的單個雙引號,替換字符串中的:
'"id1":' -> '"id1":"' //即
'"id1":"352677239567885445'
//2效拭、再在最后加單個雙引號:
'"id1":"352677239567885445"'
最后再用一次JSON.parse解析暂吉,就能解析為字符串了胖秒。
3、廢話完上代碼
//主入口
function getRealJsonData(baseStr) {
if (!baseStr || typeof baseStr != 'string') return;
var jsonData = null;
try {
jsonData = JSON.parse(baseStr);
} catch (err){
return null;
}
var needReplaceStrs = [];
loopFindArrOrObj(jsonData,needReplaceStrs);
needReplaceStrs.forEach(function (replaceInfo) {
var matchArr = baseStr.match(eval('/"'+ replaceInfo.key + '":[0-9]{15,}/'));
if (matchArr) {
var str = matchArr[0];
var replaceStr = str.replace('"' + replaceInfo.key + '":','"' + replaceInfo.key + '":"');
replaceStr += '"';
baseStr = baseStr.replace(str,replaceStr);
}
});
var returnJson = null;
try {
returnJson = JSON.parse(baseStr);
}catch (err){
return null;
}
return returnJson;
}
//遍歷對象類型的
function getNeedRpStrByObj(obj,needReplaceStrs) {
for (var key in obj) {
var value = obj[key];
if (typeof value == 'number' && value > 9007199254740992){
needReplaceStrs.push({key:key});
}
loopFindArrOrObj(value,needReplaceStrs);
}
}
//遍歷數(shù)組類型的
function getNeedRpStrByArr(arr,needReplaceStrs) {
for(var i=0; i<arr.length; i++){
var value = arr[i];
loopFindArrOrObj(value,needReplaceStrs);
}
}
//遞歸遍歷
function loopFindArrOrObj(value,needRpStrArr) {
var valueTypeof = Object.prototype.toString.call(value);
if (valueTypeof == '[object Object]') {
needRpStrArr.concat(getNeedRpStrByObj(value,needRpStrArr));
}
if (valueTypeof == '[object Array]') {
needRpStrArr.concat(getNeedRpStrByArr(value,needRpStrArr));
}
}
//使用:
var testString = '{"a":{"b":{"n":[{"a":"138476506","ad":"us","se":"測",' +
'"e":"0","r":"0.0","s":"1","t":"2","c":"0","id1":352677239567885445,' +
'"id2":472667239127885446}]},"q":"52"}}';
var data = getRealJsonData(testString);//直接放要解析的json字符串
console.log(data);
打個斷點看一下:
被替換為字符串啦慕的,而且數(shù)值正確阎肝,大功告成。