首頁 > 軟體

Swagger異常定位紀實Swagger設計問題分析

2022-02-21 16:00:34

前言

swagger ui是一個採用註解驅動的介面檔案工具,目前已支援標準的open api v3規範協定,所以不僅可以在java專案裡使用,每個語言都有相應的open api實現。專案整合swagger後,可以生成匯出open api v3格式化的後設資料集,有了這個介面後設資料,你可以在任何支援v3協定的ui上展示你的api資訊。在前後端分離的專案中,swagger ui的出現,大大提高了前後端聯調的效率。

swagger ui在解析註解標註的後設資料資訊時,特別場景下會拋異常,而且拋的異常沒有直觀的有價值的異常資訊,所以深入的debug了一番,雖然最後問題解決很簡單,但是過程非常曲折。故將bug定位過程記錄在此。

異常資訊

這個異常只會在載入swagger-ui的頁面時會丟擲,每次重新整理頁面,獲取一次api介面就會觸發一次異常。

異常分析

@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;
}

如上是異常相關的程式碼。從異常資訊表象來看,是一個強轉導致的問題,程式碼試圖將一個空的字串轉換成數值型別導致異常丟擲。並且是getExample時丟擲的異常,這裡需要了解swagger ui的載入過程和基礎架構才能直接定位。swagger中的example是為了在生成的api doc中,給出相關欄位的呼叫範例,並在觸發介面呼叫時,預設自動填充example的值。這裡顯然是哪個地方的example設定不合理導致的異常。那麼,接下來要做的就是找到這個空字串的原始程式碼。

DEBUG找到真實原因

藉助IDEA的debug功能,點選異常後面的create breakpoint,在觸發異常的地方打上斷點。觸發異常,進入斷點,獲取到了關鍵資訊

一個被描述為app id的欄位,用這個資訊全域性搜尋,得到如下的結果:

有三個相關的Model實體,首先,這三個Model的appId欄位都沒有設定過example屬性,所以,到這一步,可以先下一個小的結論,不是我們設定的example導致的問題,預設在不設定的情況下,example的預設值就是空字串。然後肯定只有其中一個有問題,因為異常只會觸發一次。在不知道結果情況下,依次對這三個Model的appId欄位加上正確的example描述,經測試,只有GetAppBannerRequestDTO加上時,異常才消失,罪魁禍首就是它了。但是,為什麼呢?其他兩個Model為啥就沒有問題呢?在博主交叉測驗後,發現了最終的原因。

結論及注意事項

當Model作用於請求的接收引數時,並且請求的型別為GET,那麼Swagger Ui會自動收集Model所有屬性的examole引數,因為這個引數是字串型別,所以會做一個型別轉換動作。當欄位型別為數值型別,又有沒手動設定example的值,那麼Swagger框架拿到的是個空字串,強轉空字串就拋異常了。而如果請求是POST,就不會觸發這段邏輯,所以同為攜帶數值型別DTO的ImgReplaceRequestDTO沒有問題。如果不是接收引數,作為響應引數,也不會觸發這段邏輯,故而AppBannerResponseVO也就沒有問題了。所以,需要注意的就是當DTO作用於GET請求的接收引數時,切記給所有的數值型別加上正確的example屬性

後記

博主認為這裡屬於一個設計缺陷,而不是我們的使用問題。在獲取example的邏輯裡,第一段程式碼就判斷了example是否為null。這表明了example有可能為空,但是預設值卻設定了一個空字串。代表不手動將example設定為null,這段判null返回的邏輯就永遠跑不到,而且沒人會這麼做,手動給example設定為null。況且,在觸發異常的這種場景下,框架不能強制使用者設定example這種操作。在github倉庫追蹤這塊程式碼發現,目前Swagger ui已經邁入了3.x版本,全面基於open api v3協定規範設計。所以,這部分程式碼完全不一樣了。而存檔的1.5x版本這個問題依舊。

下面是3.x的處理方式,雖然example的預設值還是“”。但是通過NotBlank判斷了下,所以不會觸發異常了

為啥不直接升級3.X?

3.x版本既然已經修復了,為啥不直接升級到3.x版本呢?可能有人會有這個疑問。Swagger3.x版本屬於一個大跨度的迭代版本,和之前的版本完全不相容,3.x主要面向了open api v3規範協定設計實現,註解實體等模型都是一一對應的。而在這個版本之前的1.5x系列版本是Swagger自己設計的api模型。所以程式碼層上面完全不相容,升級的工作量會非常大。不過,新專案還是推薦使用3.x版本,這個版本的api資料更通用。可以根據api的資料生成各種語言的使用者端包。就像proto生成使用者端包一樣。

以上就是Swagger異常定位紀實Swagger設計問題分析的詳細內容,更多關於Swagger異常定位Swagger設計的資料請關注it145.com其它相關文章!


IT145.com E-mail:sddin#qq.com