JSON是一种轻量级的数据交换格式,基于ECMAScript的一个子集设计,采用完全独立于编程语言的文本格式来表示数据。它易于人类阅读和编写,同时也便于机器解析和生成,这使得JSON在数据交换中具有高效性。
JSON也就成了每一个程序员每天都要使用一个小类库。无论你使用的谷歌的gson
,阿里巴巴的fastjson
,框架自带的jackjson
,还是第三方的hutool的json等。总之,每天都要和他打交道。
但是,却在阴沟里翻了船。
1、平平无奇的接口
java
/**
* 获取vehicleinfo 信息
*
* @RequestParam vehicleId
* @return Vehicle的json字符串
*/
String loadVehicleInfo(Integer vehicleId);
该接口就是通过一个vehicleId
参数获取Vehicle
对象,返回的数据是Vehicle
的JSON字符串,也就是将获取的对象信息序列化成JSON字符串了。
2、无懈可击的引用
java
String jsonStr = auctVehicleService.loadVehicleInfo(freezeDetail.getVehicle().getId());
if (StringUtils.isNotBlank(jsonStr)) {
Vehicle vehicle = JSON.parseObject(jsonStr, Vehicle.class);
if (vehicle != null) {
// 后续省略 ...
}
}
看似无懈可击的引用,隐藏着魔鬼。为什么无懈可击,因为做了健壮性的判断,非空字符串、非空对象等的判断,根除了空指针异常。
但是,魔鬼隐藏在哪里呢?
3、故障引发
线上直接出现类似的故障(此报错信息为线下模拟)。
现在测试为什么没有问题:主要的测试了基础数据,测试的数据中恰好没有Date
类型的数据,所以线下没有测出来。
4、故障原因分析
从报错日志可以看出,是因为日期类型的参数导致的。Mar 24, 2025 1:23:10 PM
这样的日期格式无法使用Fastjson
解析。
深入代码查看:
java
@Override
public String loadVehicleInfo(Integer vehicleId) {
String key = VEHICLE_KEY + vehicleId;
Object obj = cacheService.get(key);
if (null != obj && StringUtils.isNotEmpty(obj.toString())
&& !"null".equals(obj.toString())) {
String result = (String)obj;
return result;
}
String json = null;
try {
Vehicle vInfo = overrideVehicleAttributes(vehicleId);
// 使用了Gson序列化对象
json = gson.toJson(vInfo);
cacheService.setExpireSec(key, gson.toJson(vInfo), 5 * 60);
} catch (Exception e) {
cacheService.setExpireSec(key, "", 1 * 60);
} finally {
}
return json;
}
原来接口的实现里面采用了谷歌的Gson
对返回的对象做了序列化。调用的地方又使用了阿里巴巴的Fastjson
发序列化,导致参数解析异常。
完蛋,上榜是要被扣工资的!!!
5、小结
问题虽小,但是影响却很大。坊间一直讨论着,程序员为什么不能写出没有bug的程序。这也许是其中的一种答案吧。
肉疼,被扣钱了!!!
--END--
喜欢就点赞收藏,也可以关注我的微信公众号:编程朝花夕拾