由Json自動轉換造成精度丟失引發的血案……


兩天!整整花了兩天才搞定的一個小問題!

先簡述一下問題:

寫一個小系統,前端用Vue.js+axios,后端用php寫的restful服務。axios負責進行與服務器端的api調用。訂單ID是用php實現的snowflake算法。夠簡單吧?

問題:當從前端通過axios調用后端服務創建訂單,創建成功后返回訂單ID。這是夠簡單的邏輯吧?但狗血的啊,前端收到的訂單ID與服務器端生成的訂單ID竟然不相同,而且總是相差幾位。可我的訂單ID用的是字符串啊。。。。(想當然引發的問題。后面再說)

排查:

1、首先用postman進行服務器端的接口測試。相同的數據,通過postman創建訂單正常,返回的訂單ID也正常。

2、在網上找了一下,懷疑是axios跨域二次請求造成的。(后來回頭細想,這個是無厘頭。為什么呢?如果是二次請求造成的,返回的訂單ID不可能是如此的有規律,不會只相差固定的幾位啊。snowflake算法是加時間戳的,時間變化造成的ID變形是非常大的。)但還是排除二次請求的問題。網上有講對於REQUEST_METHOD為OPTIONS的為二次請求,可以人家根本沒有請求啊。甚至為了排查,連wireshark都用上了,抓包確認客戶端確確實實只調用了一次!!

3、后來擔心是不是axios異步提交造成的?(可明明已經排除重新提交了。但還是決定要試試)因為加了token機制。加了令牌后,通過postman可以提交,但axios就不能提交了,提示令牌丟失。

4、后來甚至都懷疑是不是服務器端使用的ID生成算法有問題。將php版本的snowflake算法換成了C語言版本,並做成了php擴展模式形式。但,濤聲依舊!絕望了。

5、打開apache的dumpio模塊,將respone寫到日志。然后清清楚楚的看到respone中的id是正常的。

6、既然服務器端到最后輸出都是正確的,那就先檢查axios接到的原始輸入是否正確。

7、在axios中注冊transformResponse,顯示原始數據。

transformResponse: [function(data) {
       console.log(data);
       return data;
     }]

打開瀏覽器的F12,能看到終端輸出(console.log)的內容,數據是正確的!!再次看解析后的值,又是錯誤的!那問題就在接到原始數據到獲取解析值之間。終於縮小問題的定位范圍了。

在axios的then函數中,最開始進行輸出:

console.log(res.data);

值是正確的。添加解析后輸出:

console.log(res.data);

var data = JSON.parse(res.data);
console.log(data);

值是錯誤的!!!

到此終於能定位是解析的時候出錯了。但為什么解析會造成這個問題呢?

在終端上比較前后輸出的時候,有一個細節引起了我的錯誤。

token: 6412591390922670080

token字段前后沒有引號!!!!沒有引號意味着整型!!!!

終於找到問題了,服務器將id當成了長整型(token使用了與ID生成相同的算法函數)。長整型在客戶端解析的時候造成了精度丟失。

回頭看服務器的ID生成算法,原來使用的是RETURN_LONG,原來如此。

將算法中的Long型ID通過sprintf輸出為String,然后輸出。擴展模塊更新,重啟,問題解決!!!

意外收獲,將snowflake從php版本換成C語言版本,用php擴展模塊加載后,性能提升比較明顯。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM