Swagger異常定位紀實Swagger設計問題分析
前言
swagger ui是一個采用注解驅動的接口文檔工具,目前已支持標準的open api v3規(guī)范協(xié)議,所以不僅可以在java項目里使用,每個語言都有相應的open api實現(xiàn)。項目集成swagger后,可以生成導出open api v3格式化的元數(shù)據(jù)集,有了這個接口元數(shù)據(jù),你可以在任何支持v3協(xié)議的ui上展示你的api信息。在前后端分離的項目中,swagger ui的出現(xiàn),大大提高了前后端聯(lián)調的效率。
swagger ui在解析注解標注的元數(shù)據(jù)信息時,特別場景下會拋異常,而且拋的異常沒有直觀的有價值的異常信息,所以深入的debug了一番,雖然最后問題解決很簡單,但是過程非常曲折。故將bug定位過程記錄在此。
- 影響的Swagger版本:1.5.x
- Swagger core:https://github.com/swagger-api/swagger-core
異常信息
這個異常只會在加載swagger-ui的頁面時會拋出,每次刷新頁面,獲取一次api接口就會觸發(fā)一次異常。
異常分析
@JsonProperty("x-example") public Object getExample() { if (example == null) { return null; } try { if (BaseIntegerProperty.TYPE.equals(type)) { return Long.valueOf(example); } else if (DecimalProperty.TYPE.equals(type)) { return Double.valueOf(example); } else if (BooleanProperty.TYPE.equals(type)) { if ("true".equalsIgnoreCase(example) || "false".equalsIgnoreCase(defaultValue)) { return Boolean.valueOf(example); } } } catch (NumberFormatException e) { LOGGER.warn(String.format("Illegal DefaultValue %s for parameter type %s", defaultValue, type), e); } return example; }
如上是異常相關的代碼。從異常信息表象來看,是一個強轉導致的問題,代碼試圖將一個空的字符串轉換成數(shù)值類型導致異常拋出。并且是getExample時拋出的異常,這里需要了解swagger ui的加載過程和基礎架構才能直接定位。swagger中的example是為了在生成的api doc中,給出相關字段的調用示例,并在觸發(fā)接口調用時,默認自動填充example的值。這里顯然是哪個地方的example設置不合理導致的異常。那么,接下來要做的就是找到這個空字符串的原始代碼。
DEBUG找到真實原因
借助IDEA的debug功能,點擊異常后面的create breakpoint,在觸發(fā)異常的地方打上斷點。觸發(fā)異常,進入斷點,獲取到了關鍵信息
一個被描述為app id的字段,用這個信息全局搜索,得到如下的結果:
有三個相關的Model實體,首先,這三個Model的appId字段都沒有設置過example屬性,所以,到這一步,可以先下一個小的結論,不是我們設置的example導致的問題,默認在不設置的情況下,example的默認值就是空字符串。然后肯定只有其中一個有問題,因為異常只會觸發(fā)一次。在不知道結果情況下,依次對這三個Model的appId字段加上正確的example描述,經測試,只有GetAppBannerRequestDTO加上時,異常才消失,罪魁禍首就是它了。但是,為什么呢?其他兩個Model為啥就沒有問題呢?在博主交叉測驗后,發(fā)現(xiàn)了最終的原因。
結論及注意事項
當Model作用于請求的接收參數(shù)時,并且請求的類型為GET,那么Swagger Ui會自動收集Model所有屬性的examole參數(shù),因為這個參數(shù)是字符串類型,所以會做一個類型轉換動作。當字段類型為數(shù)值類型,又有沒手動設置example的值,那么Swagger框架拿到的是個空字符串,強轉空字符串就拋異常了。而如果請求是POST,就不會觸發(fā)這段邏輯,所以同為攜帶數(shù)值類型DTO的ImgReplaceRequestDTO沒有問題。如果不是接收參數(shù),作為響應參數(shù),也不會觸發(fā)這段邏輯,故而AppBannerResponseVO也就沒有問題了。所以,需要注意的就是當DTO作用于GET請求的接收參數(shù)時,切記給所有的數(shù)值類型加上正確的example屬性
后記
博主認為這里屬于一個設計缺陷,而不是我們的使用問題。在獲取example的邏輯里,第一段代碼就判斷了example是否為null。這表明了example有可能為空,但是默認值卻設置了一個空字符串。代表不手動將example設置為null,這段判null返回的邏輯就永遠跑不到,而且沒人會這么做,手動給example設置為null。況且,在觸發(fā)異常的這種場景下,框架不能強制使用者設置example這種操作。在github倉庫追蹤這塊代碼發(fā)現(xiàn),目前Swagger ui已經邁入了3.x版本,全面基于open api v3協(xié)議規(guī)范設計。所以,這部分代碼完全不一樣了。而存檔的1.5x版本這個問題依舊。
下面是3.x的處理方式,雖然example的默認值還是“”。但是通過NotBlank判斷了下,所以不會觸發(fā)異常了
為啥不直接升級3.X?
3.x版本既然已經修復了,為啥不直接升級到3.x版本呢?可能有人會有這個疑問。Swagger3.x版本屬于一個大跨度的迭代版本,和之前的版本完全不兼容,3.x主要面向了open api v3規(guī)范協(xié)議設計實現(xiàn),注解實體等模型都是一一對應的。而在這個版本之前的1.5x系列版本是Swagger自己設計的api模型。所以代碼層上面完全不兼容,升級的工作量會非常大。不過,新項目還是推薦使用3.x版本,這個版本的api數(shù)據(jù)更通用??梢愿鶕?jù)api的數(shù)據(jù)生成各種語言的客戶端包。就像proto生成客戶端包一樣。
以上就是Swagger異常定位紀實Swagger設計問題分析的詳細內容,更多關于Swagger異常定位Swagger設計的資料請關注腳本之家其它相關文章!
相關文章
基于java SSM springboot實現(xiàn)景區(qū)行李寄存管理系統(tǒng)
這篇文章主要介紹了基于java SSM springboot實現(xiàn)的景區(qū)行李寄存管理系統(tǒng),本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-08-08IDEA “Cannot resolve symbol”爆紅問題解決
最近發(fā)現(xiàn)個問題,IDEA 無法識別同一個 package 里的其他類,將其顯示為紅色,本文就來介紹一下IDEA “Cannot resolve symbol”爆紅問題解決,感興趣的可以了解一下2023-10-10基于SpringBoot服務端表單數(shù)據(jù)校驗的實現(xiàn)方式
這篇文章主要介紹了基于SpringBoot服務端表單數(shù)據(jù)校驗的實現(xiàn)方式,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-10-10Spring boot如何快速的配置多個Redis數(shù)據(jù)源
這篇文章主要介紹了Spring boot如何快速的配置多個Redis數(shù)據(jù)源,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2020-06-06