由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扩展模块加载后,性能提升比较明显。

posted @ 2018-06-13 17:16  qinsg  阅读(1893)  评论(0编辑  收藏  举报