日韩成人免费在线_国产成人一二_精品国产免费人成电影在线观..._日本一区二区三区久久久久久久久不

當前位置:首頁 > 科技  > 軟件

一個詭異的Json反序列化問題

來源: 責編: 時間:2024-06-28 17:16:02 192觀看
導讀前言最近我在做知識星球中的商品秒殺系統,昨天遇到了一個詭異的json反序列化問題,感覺挺有意思的,現在拿出來跟大家一起分享一下,希望對你會有所幫助。案發現場我最近在做知識星球中的商品秒殺系統,寫了一個filter,獲取用戶

前言

最近我在做知識星球中的商品秒殺系統,昨天遇到了一個詭異的json反序列化問題,感覺挺有意思的,現在拿出來跟大家一起分享一下,希望對你會有所幫助。MjP28資訊網——每日最新資訊28at.com

案發現場

我最近在做知識星球中的商品秒殺系統,寫了一個filter,獲取用戶請求的header中獲取JWT的token信息。MjP28資訊網——每日最新資訊28at.com

然后根據token信息,獲取到用戶信息。MjP28資訊網——每日最新資訊28at.com

在轉發到業務接口之前,將用戶信息設置到用戶上下文當中。MjP28資訊網——每日最新資訊28at.com

這樣接口中的業務代碼,就能通過用戶上下文,獲取到當前登錄的用戶信息了。MjP28資訊網——每日最新資訊28at.com

我們的token和用戶信息,為了性能考慮都保存到了Redis當中。MjP28資訊網——每日最新資訊28at.com

用戶信息是一個json字符串。MjP28資訊網——每日最新資訊28at.com

當時在用戶登錄接口中,將用戶實體,使用fastjson工具,轉換成了字符串:MjP28資訊網——每日最新資訊28at.com

JSON.toJSONString(userDetails);

保存到了Redis當中。MjP28資訊網——每日最新資訊28at.com

然后在filter中,通過一定的key,獲取Redis中的字符串,反序列化成用戶實體。MjP28資訊網——每日最新資訊28at.com

使用的同樣是fastjson工具:MjP28資訊網——每日最新資訊28at.com

JSON.parseObject(json, UserEntity.class);

但在反序列化的過程中,filter拋異常了:com.alibaba.fastjson.JSONException: illegal identifier : /pos 1, line 1, column 2{/"accountNonExpired/":true,/"accountNonLocked/":true,/"authorities/":[{/"authority/":/"admin/"}],/"credentialsNonExpired/":true,/"enabled/":true,/"id/":13,/"password/":/"$2a$10$o3XfeGr0SHStAwLuJRW6y.kE0UTerQfv3SXrAcVLuJ6M3hEsC9RKe/",/"roles/":[/"admin/"],/"username/":/"admin/"}MjP28資訊網——每日最新資訊28at.com

2 分析問題

我剛開始以為是json數據格式有問題。MjP28資訊網——每日最新資訊28at.com

將json字符串復制到在線json工具:https://www.sojson.com,先去掉化之后,再格式數據,發現json格式沒有問題:MjP28資訊網——每日最新資訊28at.com

圖片圖片MjP28資訊網——每日最新資訊28at.com

然后寫了一個專門的測試類,將日志中打印的json字符串復制到json變量那里,使用JSON.parseObject方法,將json字符串轉換成Map對象:MjP28資訊網——每日最新資訊28at.com

public class Test {    public static void main(String[] args) {        String json = "{/"accountNonExpired/":true,/"accountNonLocked/":true,/"authorities/":[{/"authority/":/"admin/"}],/"credentialsNonExpired/":true,/"enabled/":true,/"id/":13,/"password/":/"$2a$10$o3XfeGr0SHStAwLuJRW6y.kE0UTerQfv3SXrAcVLuJ6M3hEsC9RKe/",/"roles/":[/"admin/"],/"username/":/"admin/"}";        Map map = JSON.parseObject(json, Map.class);        // 輸出解析后的 JSON 對象        System.out.println(map);    }}

執行結果:MjP28資訊網——每日最新資訊28at.com

{password=$2a$10$o3XfeGr0SHStAwLuJRW6y.kE0UTerQfv3SXrAcVLuJ6M3hEsC9RKe, credentialsNnotallow=true, roles=["admin"], accountNnotallow=true, id=13, authorities=[{"authority":"admin"}], enabled=true, accountNnotallow=true, username=admin}

竟然轉換成功了。MjP28資訊網——每日最新資訊28at.com

這就讓我有點懵逼了。。。MjP28資訊網——每日最新資訊28at.com

為什么相同的json字符串,在Test類中能夠正常解析,而在filter當中卻不行?MjP28資訊網——每日最新資訊28at.com

當時怕搞錯了,debug了一下filter,發現獲取到的json數據,跟Test類中的一模一樣:MjP28資訊網——每日最新資訊28at.com

圖片圖片MjP28資訊網——每日最新資訊28at.com

帶著一臉的疑惑,我做了下面的測試。MjP28資訊網——每日最新資訊28at.com

莫非是反序列化工具有bug?MjP28資訊網——每日最新資訊28at.com

3 改成gson工具

我嘗試了一下將json的反序列化工具改成google的gson,代碼如下:MjP28資訊網——每日最新資訊28at.com

Map map = new Gson().fromJson(userJson, Map.class);

運行之后,報了一個新的異常:com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was STRING at line 1 column 2 path $MjP28資訊網——每日最新資訊28at.com

這里提示json字符串中包含了:$。MjP28資訊網——每日最新資訊28at.com

而$是特殊字符,password是做了加密處理的,里面包含$和.,這兩種特殊字符。MjP28資訊網——每日最新資訊28at.com

為了快速解決問題,我先將這兩個特字符替換成空字符串:MjP28資訊網——每日最新資訊28at.com

json = json.replace("$","").replace(".","");

日志中打印出的json中的password,已經不包含這兩個特殊字符了:MjP28資訊網——每日最新資訊28at.com

2a10o3XfeGr0SHStAwLuJRW6ykE0UTerQfv3SXrAcVLuJ6M3hEsC9RKe

但調整之后代碼報了下面的異常:com.google.gson.JsonSyntaxException: com.google.gson.stream.MalformedJsonException: Expected name at line 1 column 2 path $.MjP28資訊網——每日最新資訊28at.com

跟剛剛有點區別,但還是有問題。MjP28資訊網——每日最新資訊28at.com

4 改成jackson工具

我又嘗試了一下json的反序列化工具,改成Spring自帶的的jackson工具,代碼如下:MjP28資訊網——每日最新資訊28at.com

ObjectMapper objectMapper = new ObjectMapper();try {    Map map = objectMapper.readValue(json, Map.class);} catch (JsonProcessingException e) {    e.printStackTrace();}

調整之后,反序列化還是報錯:com.fasterxml.jackson.core.JsonParseException: Unexpected character ('/' (code 92)): was expecting double-quote to start field nameMjP28資訊網——每日最新資訊28at.com

3種反序列化工具都不行,說明應該不是fastjson的bug導致的當前json字符串,反序列化失敗。MjP28資訊網——每日最新資訊28at.com

到底是什么問題呢?MjP28資訊網——每日最新資訊28at.com

5 轉義

之前的數據,我在仔細看了看。MjP28資訊網——每日最新資訊28at.com

里面是對雙引號,是使用了轉義的,具體是這樣做的:/"。MjP28資訊網——每日最新資訊28at.com

莫非還是這個轉義的問題?MjP28資訊網——每日最新資訊28at.com

其實我之前已經注意到了轉義的問題,但使用Test類測試過,沒有問題。MjP28資訊網——每日最新資訊28at.com

當時的代碼是這樣的:MjP28資訊網——每日最新資訊28at.com

public class Test {    public static void main(String[] args) {        String json = "{/"accountNonExpired/":true,/"accountNonLocked/":true,/"authorities/":[{/"authority/":/"admin/"}],/"credentialsNonExpired/":true,/"enabled/":true,/"id/":13,/"password/":/"$2a$10$o3XfeGr0SHStAwLuJRW6y.kE0UTerQfv3SXrAcVLuJ6M3hEsC9RKe/",/"roles/":[/"admin/"],/"username/":/"admin/"}";        Map map = JSON.parseObject(json, Map.class);        // 輸出解析后的 JSON 對象        System.out.println(map);    }}

里面也包含了一些轉義字符。MjP28資訊網——每日最新資訊28at.com

我帶著試一試的心態,接下來,打算將轉義字符去掉。MjP28資訊網——每日最新資訊28at.com

看看原始的json字符串,解析有沒有問題。MjP28資訊網——每日最新資訊28at.com

怎么去掉轉義字符呢?MjP28資訊網——每日最新資訊28at.com

手寫工具類,感覺不太好,可能會寫漏一些特殊字符的場景。MjP28資訊網——每日最新資訊28at.com

我想到了org.apache.commons包下的StringEscapeUtils類,它里面的unescapeJava方法,可以輕松去掉Java代碼中的轉義字符。MjP28資訊網——每日最新資訊28at.com

于是,我調整了一下代碼:MjP28資訊網——每日最新資訊28at.com

json = StringEscapeUtils.unescapeJava(json);JSON.parseObject(json, UserEntity.class);

這樣處理之后,發現反序列化成功了。MjP28資訊網——每日最新資訊28at.com

總結

這個問題最終發現還是轉義的問題。MjP28資訊網——每日最新資訊28at.com

那么,之前Test類中json字符串,也使用了轉義,為什么沒有問題?MjP28資訊網——每日最新資訊28at.com

當時的代碼是這樣的:MjP28資訊網——每日最新資訊28at.com

public class Test {    public static void main(String[] args) {        String json = "{/"accountNonExpired/":true,/"accountNonLocked/":true,/"authorities/":[{/"authority/":/"admin/"}],/"credentialsNonExpired/":true,/"enabled/":true,/"id/":13,/"password/":/"$2a$10$o3XfeGr0SHStAwLuJRW6y.kE0UTerQfv3SXrAcVLuJ6M3hEsC9RKe/",/"roles/":[/"admin/"],/"username/":/"admin/"}";        Map map = JSON.parseObject(json, Map.class);        System.out.println(map);    }}

但在filter中的程序,在讀取到這個json字符串之后,發現該字符串中包含了/轉義符號,程序自動把它變成了///。MjP28資訊網——每日最新資訊28at.com

調整一下Test類的main方法,改成三個斜杠的json字符串:MjP28資訊網——每日最新資訊28at.com

public static void main(String[] args) {    String json = "{///"accountNonExpired///":true,///"accountNonLocked///":true,///"authorities///":[{///"authority///":///"admin///"}],///"credentialsNonExpired///":true,///"enabled///":true,///"id///":13,///"password///":///"$2a$10$o3XfeGr0SHStAwLuJRW6y.kE0UTerQfv3SXrAcVLuJ6M3hEsC9RKe///",///"roles///":[///"admin///"],///"username///":///"admin///"}";    Map map = JSON.parseObject(json, Map.class);    System.out.println(map);}

執行結果:Exception in thread "main" com.alibaba.fastjson.JSONException: illegal identifier : /pos 1, line 1, column 2{/"accountNonExpired/":true,/"accountNonLocked/":true,/"authorities/":[{/"authority/":/"admin/"}],/"credentialsNonExpired/":true,/"enabled/":true,/"id/":13,/"password/":/"$2a$10$o3XfeGr0SHStAwLuJRW6y.kE0UTerQfv3SXrAcVLuJ6M3hEsC9RKe/",/"roles/":[/"admin/"],/"username/":/"admin/"}拋出了跟文章最開始一樣的異常。MjP28資訊網——每日最新資訊28at.com

說明其實就是轉義的問題。MjP28資訊網——每日最新資訊28at.com

之前,我將項目的日志中的json字符串,復制到idea的Test的json變量中,當時將最外層的雙引號一起復制過來了,保存的是1個斜杠的數據。MjP28資訊網——每日最新資訊28at.com

這個操作把我誤導了。MjP28資訊網——每日最新資訊28at.com

而后面從在線的json工具中,把相同的json字符串,復制到idea的Test的json變量中,在雙引號當中粘貼數據,保存的卻是3個斜杠的數據,它會自動轉義。MjP28資訊網——每日最新資訊28at.com

讓我意識到了問題。MjP28資訊網——每日最新資訊28at.com

好了,下次如果遇到類似的問題,可以直接使用org.apache.commons包下的StringEscapeUtils類,先去掉轉義,再反序列化,這樣可以快速解決問題。MjP28資訊網——每日最新資訊28at.com

此外,這次使用了3種不同的反序列化工具,也看到了其中的一些差異。MjP28資訊網——每日最新資訊28at.com

本文鏈接:http://www.www897cc.com/showinfo-26-97297-0.html一個詭異的Json反序列化問題

聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。郵件:2376512515@qq.com

上一篇: RecyclerView的緩存機制及使用策略

下一篇: 圖解 Jenkins Pipeline 的前端自動化部署,用上后真香!

標簽:
  • 熱門焦點
Top 主站蜘蛛池模板: 长武县| 达尔| 富锦市| 遂川县| 甘德县| 铅山县| 平和县| 精河县| 会东县| 青岛市| 宜阳县| 壶关县| 佛冈县| 金塔县| 泗洪县| 纳雍县| 旬邑县| 尼勒克县| 含山县| 嘉祥县| 彩票| 巴彦淖尔市| 泾川县| 尼勒克县| 中宁县| 漾濞| 六枝特区| 商南县| 黎平县| 鄄城县| 克拉玛依市| 巧家县| 淅川县| 灯塔市| 定结县| 东莞市| 海城市| 上林县| 通榆县| 临高县| 长兴县|