Fastjson升级问题
目录
问题背景
Fastjson版本由于存在安全漏洞,公司要求各个部门对所属应用中存在低于1.2.83版本的fastjson升级应用升级到1.2.83,即低版本fastjson升级到高版本。
问题现象
Caused by: com.alibaba.fastjson.JSONException: syntax error, expect }, actual , |
问题堆栈信息
Method: checkLogin, exception: com.alibaba.fastjson.JSONException: syntax error,expect },actual ,dubbo version: 2.4.7,current host: 172.21.21.38 |
问题解决之路(思考方向)
复现问题
- 第一反应是从redis获取到字符串不满足fastjson格式
但是如果不是json格式,那么早就应该报问题了。
然后加日志,输出从redis中的取出的字符串,发现字符串格式正常且符合json格式:
[{"userInfo":"","jun":"","jum":"","nickName":"xxxxxx","openUserFlag":"open","userName":"xxxx","userId":"111111","yzToken":"","expiredTime":"1661338531800","token":"xxxxxx","moniPharmacistId":"","result":0,"userLeverId":1,"loginTime":"1661338531800","gltoken":"","jud":"","member":null,"userIp":"222.191.226.242","customer":{"registerIP":"","companyName":"","channel":"","source":10,"type":0,"password":"xxxxxx","province":"0","id":"xxxxxxx","modifyDate":null,"nickName":"13270162613","telephone":"","version":"","userLevelStartTime":null,"isOldUser":0,"realPassword":"","district":"","name":"","partnerType":0,"userType":"","enterCount":0,"requestTag":"","cardNumber":"","isBindMobileToWexin":0,"loginMobile":"xxxxxx","status":1,"income":0,"ipaddress":"127.0.0.1","gender":1,"city":"","openId":null,"ecUId":0,"loginEmail":"","isDeleted":0,"cellphone":"","promoCode":"","popType":0,"email":"","userLevelEndTime":null,"userLevelId":1,"createDate":{"date":21,"hours":11,"seconds":17,"month":4,"timezoneOffset":-480,"year":120,"minutes":59,"time":1590033557000,"day":4},"birthDay":null,"address":"","salt":"L1TIwT","partnerName":"","userscore":0,"baoGangUser":false,"ecUserId":xxxxxx,"userId":"","lastLoginTime":null,"partnerId":""}}] |
2 . 本地复现问题
本地使用junit来模拟“将redis 存入用户数据,然后调用出错的代码取数据”这个流程,结果正常,正常,正常!结果怎么会正常呢?
开始怀疑是两个字符串不一样,对比发现字符串中createDate不一样。
json字符串中异常的createDate,如下:
正常的createDate,如下:
3. 怀疑json包混合使用导致(createDate怎么会是这种格式?)
createDate在类中定义的是java.util.Date类型,json成字符串怎么会是这种格式呢?
什么操作会导致它变成这样了(它到底经历了什么)?
开始怀疑net.sf.json包和fastjson混用导致的,经过验证发现,果然这种格式正是net.sf.json包中的处理方式(心里一万头羊驼奔驰)。
-
问题原因
net.sf.json包中的JSONArray和JSONObject会将java.util.Date类型的createDate格式化为json字符串,即
"createDate":{"date":31,"hours":18,"seconds":14,"year":121,"minutes":53,"time":1622458394000,"day":1},
而我们实际需要的时long类型的值,或者指定日期格式的字符串。
总的来说:
项目中net.sf.json包和alibaba 混合使用,使用net.sf.json包中的类将对象格式化后存入到Redis,解析redis中的字符串却使用的fastjson。
那么怎么混用的呢?神奇的操作(听我说,谢谢你!!!)。
在一段业务中,存入redis中的用户信息使用net.sf.json包格式化为字符串的,如下:
public void setUserInfoToRedis(UserInfo userInfo,EcuserCustomer customer,int type) {
//此处的JSONArray是net.sf.json.JSONArray而不是fastjson中的
String value = String.valueOf(JSONArray.fromObject(userInfo));
if (type == 1) {
String key = customer.getId() + USERINFO;
int ttl = PassportApolloConfigUtil.getConfigIntVal("userinfoweek_expire");
RedisUtils.set(key,value,Long.valueOf(ttl));
} else {
set(customer.getId(),USERINFO,value);
}
}
而从redis中取出字符串后,使用alibaba的fastjson解析的,如下:
public static UserInfo toUserInfo(String value){
return com.alibaba.fastjson.JSONArray.parseArray(value).getObject(0,UserInfo.class);
}
目前看低版本支持net.sf.json和alibaba混用,但是高版本fastjson进行了优化,不再兼容,所以升级导致报错。
问题解决
通过兜底逻辑兼容解析json字符串。
(1)针对解析报错的字符串,我们就认为是net.sf.JSON包处理的,所以我们使用net.sf包下的解析。
(2)针对可以正常解析的的json字符串,我们还是使用alibaba fastjson来解析。
处理代码如下:
public static UserInfo toUserInfo(String value) {
log.info("从redis中获取的用户信息字符串userInfoStr={}",value);
UserInfo userInfo = null;
try {
userInfo = com.alibaba.fastjson.JSONArray.parseArray(value).getObject(0,UserInfo.class);
} catch (Exception e) {
log.error("使用fast json解析字符串异常,异常信息error={},尝试使用net.sf.json解析字符串。",e.getMessage());
JSONArray jsonArray = JSONArray.fromObject(value);
JSONObject jsonObject = (JSONObject) jsonArray.get(0);
userInfo = (UserInfo) JSONObject.toBean(jsonObject,UserInfo.class);
}
return userInfo;
}
参考博客
1.时间Date格式转换为json后出现的问题处理_向上吧! 少年的博客-CSDN博客_date json
2.java中使用net.sf.json对json进行解析_shanliangliuxing的博客-CSDN博客
原文地址:https://blog.csdn.net/u014786083/article/details/126711805
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。