More
本項目僅供爬取體驗,每次訪問都會實時爬取數據,所以數據返回速度會比較慢,實際操作應該是定時爬取數據然后將數據存進數據庫,數據從數據庫返回從而提高數據返回效率。
但項目很基礎,可以作為以上各個node模塊最基礎的練手使用,希望可以幫到大家
最近在實現一個需求的時候,需要接入第三方的接口,先調用A接口,A接口返回的數據里,有一個taskId,然后再使用這個taskId請求B接口,獲取最終需要的數據。
后端使用的是node,因此最開始使用的是request-promise這個包請求第三方接口,然而在獲取A接口返回的taskId之后,調用B接口之后,B接口的響應居然是系統錯誤!簡易代碼如下
const rp = require('request-promise')const { taskId } = await rp('https://xxx.com/A')const options = { method: 'POST', uri: 'https://xxx.com/B', body: { taskId }, json: true}const result = await rp(options) // {// "errorcode": "40001",// "message": "系統錯誤",// "status": "failed"// }
接著我使用postman請求A接口,獲取新的taskId,再用新的taskId請求B接口,結果卻是正常的!
我在反復檢查代碼,確認請求的參數都是正常的格式之后,一時陷入了無盡的沉思之中。。。
發現
在做了幾次嘗試之后,我發現使用node請求得到的taskId最后兩位數都是0,即1152921504735848700,而使用postman獲取的taskId,則是比較正常的是1152921504735848759,接著我在node控制臺做如下操作
就是這么一瞬間,頓悟了。A接口里的taskId是個19位數字,而request-promise在將數據解析成json時,導致這個19位的數字丟失了精度,查了下資料,發現js的number類型有個最大安全值,即2的53次方(9007199254740992),超過這個值就會出現精度丟失的問題。 Orz
獲取正確的響應數據
由于在一開始使用request-promise包,因此獲取的taskId是丟失了精度了,因此改用了node原生的http模塊發送請求。
const req = https.request('https://xxx.com/A', (res) => { res.on('data', (chunk) => { // 由于這里獲取到的響應數據是JSON字符串,因此19位的數字只是字符串的一部分,這時獲取到的taskId就是正確的數字 console.log(`BODY: ${chunk}`); }); res.on('end', () => { console.log('No more data in response.'); }) })
雖然獲取到了正常的響應數據,但是這是個JSON字符串,接下來還要把這個字符串解析成JSON,但是用JSON.parse(),又會引起精度丟失的問題,這可真尷尬 Orz
如果這個接口是已方可控的,那么就可以把這個19位數的number轉成字符串,這樣在解析的時候就不會出錯了,但是由于是第三方接口,因此沒法改變。那么最快的解決方案,就是換種編程語言請求啊╮(╯_╰)╭
最后的解決
好吧,最后還是用了node,不過我用了比較硬核的方案實現,先在獲取的JSON字符串中,找到這個19位的數字,然后為它加上引號,這樣再用JSON.parse()解析的時候,就能保持正常的數值,這樣接下的流程就自然通了,代碼如下
let result = '{"taskId":1152921504735848759,"status":"CREATED","progress":0.0,"success":true}'// JSON.parse(result) 不為19位數補上雙引號,直接parse時,精度丟失,結果如下:// { // taskId: 1152921504735848700,// status: 'CREATED',// progress: 0,// success: true // }const taskId = result.match(/[0-9]{19}/)[0] // 正則獲取19位數字的值result = result.replace(taskId,`"${taskId}"`) // 補上雙引號const data = JSON.parse(result) // { // taskId: '1152921504735848759', // 解析出來之后是字符串,因此沒有丟失精度// status: 'CREATED',// progress: 0,// success: true // }
結語
使用node也有一段時間了,因為涉及不到大數計算,因此對于編號啊,ID啊,都是用字符串形式進行存儲的,也就一直沒有遇到這個問題。這一次居然碰上了,不得不說js在這一方面確實有點弱勢,之后也嘗試了下使用Go,python進行請求,都是能正確解析不過node使用起來還是很舒服的
以上所述是小編給大家介紹的JS大坑之19位數的Number型精度丟失問題詳解整合,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對腳本之家網站的支持!
新聞熱點
疑難解答