【問題】【SpringBoot】記一次springboot框架下用jackson解析RequestBody失敗的問題


最近項目中遇到了一個問題,費好大勁才發現問題所在,並且修復了問題,下面分享一下這個問題的定位和修復的過程,
行文有些凌亂,因為中途嘗試過N多方法,勿怪。

先說下背景:該項目用的是SpringBoot框架,主要功能為對外提供一些Restful API,使用的Servlet容器是默認的Tomcat,Json解析工具是默認的Jackson,通過@RequestBody注解來解析body。
再說下問題:用戶通過https方法調用POST方法的接口,會偶現Jackson解析Json體失敗的問題。這個問題比較離奇,同樣的數據,同樣的接口,有時候會發生解析失敗。大概成功10+次會失敗一次的頻率。報錯信息如下:

JSON parse error: Unexpected end-of-input: expected close marker for Object 
(start marker at [Source: (PushbackInputStream); line: 1, column: 1]); 
nested exception is com.fasterxml.jackson.core.io.JsonEOFException: 
Unexpected end-of-input: expected close marker for Object (start marker at 
[Source: (PushbackInputStream); line: 1, column: 1])\n at [Source: 
(PushbackInputStream); line: 1, column: 3]。

值得一提的是,line和column的值每次都會不一樣。

由於服務部署在公有雲上,依賴的周邊服務有不少,所以要先進行問題的定界。

  1. 不通過公有雲注冊的API,而是直接通過公網IP:PORT的形式調用,問題復現。排除APIG服務問題。
  2. 進入容器節點,直接調用容器內的pod ip,問題復現。排除k8s或者CCE服務的問題。
  3. 至此,已經能排除公有雲服務的問題,可以專注定位是否是框架或者實現有問題。

接下來觀察一下報錯信息,顯然是解析body體出了問題,看起來像是body體不完整導致的,而且每次提示的line和column值都不一樣,感覺是body體在哪里被截斷了。那很自然的會做以下猜測:

  1. body體本身不合法。不再贅述,推薦一個在線平台 bejson
  2. https請求對body內容做了攔截。查看請求頭中是否包含Content-Length,如果包含的話,可能就是這個值有問題,把這個Content-Length從請求頭中刪除掉
  3. body體被spring框架攔截。
  4. body體被spring內的tomcat攔截。
--server.max-http-header-size=8192000
--server.tomcat.max-http-post-size=-1
--spring.server.tomcat.max-http-header-size=52428800
--spring.server.tomcat.max-http-post-size=-1
--spring.http.multipart.max-file-size=1000m
--spring.http.multipart.max-request-size=1000m

spring和tomcat的配置有很多,找了很多參數,都沒有解決問題,行吧,只能打斷點看了。
經過測試本地無法復現,那就只能對遠程服務器上的deployment進行遠程debug。基於IDEA進行springboot工程的遠程調試方法見我之前的blog:基於IDEA對springboot做遠程調試

根據日志打出來的棧信息,不難找到是在AbstractJackson2HttpMessageConverter. readJavaType方法報的錯,這個Converter方法其實就是spring-web的http消息轉換器,
readJavaType方法定義:
private Object readJavaType(JavaType javaType, HttpInputMessage inputMessage) throws IOException
報錯信息顯示在這一行:
return this.objectMapper.readValue(inputMessage.getBody(), javaType)
這里調用了Jackson的readValue方法對message這個流進行解析,那我們從這里開始單步調試,下一步應該進到jackson的readValue方法了,此時通過ctrl+左鍵進入這個方法,
發現jackson-core的版本為2.11.2,而報錯的棧信息中jackson-core版本為2.10.2,兩邊的版本不一致?

由於spring-web版本是spring starter中指定的,帶着疑問,我嘗試着把starter的版本升級到最新的2.3.0.RELEASE,對環境上的應用進行了升級,
問題不再復現…好吧,終於解決。之前用的starter是2.2.5.RELEASE,有可能是倉庫中的該版本包有問題,亦或是這個版本下spring-web的版本就是有BUG,這個不得而知了…


免責聲明!

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



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