Net::ERR_INCOMPLETE_CHUNKED_ENCODING問題跟蹤

這兩天做項目的時候突然出現了一個問題:
這裏寫圖片描述
百思不得其解,從字面上理解的話應該是響應被截斷了。
在網上查了不少遇到這個問題的帖子,看得雲裏霧裏,和我遇到的情況都不一樣,決定還是自己來定位一下。

回顧修改歷史

查看了一下svn日誌,發現最近所做的修改裏面有一點比較可疑。就是使用了Hibernate的雙向一對多映射。

@ManyToOne
    @JoinColumn(name = "trade_type_id")
    public TradeType getTradeType() {
        return tradeType;
    }

    public void setTradeType(TradeType tradeType) {
        this.tradeType = tradeType;
    }
@OneToMany(mappedBy = "tradeType")
    public Set<MainLmmIndex> getMainLmmIndexSet() {
        return mainLmmIndexSet;
    }

    public void setMainLmmIndexSet(Set<MainLmmIndex> mainLmmIndexSet) {
        this.mainLmmIndexSet = mainLmmIndexSet;
    }

之前的接口運行得挺好,做了這個修改以後就出了問題,改回爲單向映射之後,問題消失。

查看Controller接口

@GetMapping(value = "listMainLmmIndex/{tradeTypeId}")
    public Set<MainLmmIndex> listMainLmmIndex(@PathVariable String tradeTypeId) {
        return mainLmmIndexService.listMainLmmIndex(tradeTypeId);
    }
@Transactional(readOnly = true)
    public Set<MainLmmIndex> listMainLmmIndex(String tradeTypeId) {
        TradeType tradeType = tradeTypeRepository.findOne(tradeTypeId);
        if (tradeType == null) {
            return new HashSet<MainLmmIndex>();
        } else {
            return tradeType.getMainLmmIndexSet();
        }
    }

這個地方,Controller的返回類型爲Set,這個Set是直接從映射關係中得到的,返回給前端的時候經過SpringMVC的類型轉換成爲JSON字符串(通過@RestController實現)。
那麼這樣做能看出什麼問題呢?
好像有點循環……

Fiddler查看真實響應內容

這裏寫圖片描述
由於firebug僅僅能看到一個錯誤提示,從返回值的responseText看的時候爲空,所以這裏得不到什麼有效的信息了。
由於網上有人提到說這個是由於Chrome導致的,所以嘗試使用fiddler模擬一下請求。
使用Fiddler請求之後,在查看響應時彈出一個錯誤框:
這裏寫圖片描述
這說明不是Chrome的問題,而是接口自身的問題。
既然不能查看JSON格式的響應結果,看一下Raw格式的響應結果,發現了問題所在:
這裏寫圖片描述
這個還不是響應得全貌,水平滾動條僅僅佔了全部內容的百分之五左右。
這個與預期的響應結果極爲不符,因爲查看數據庫後得知對應的數據僅僅五六條而已,每條記錄四五個字段,字符數也不多,不應該有如此之多的響應內容。
仔細查看後發現:
相應的JSON在不停地嵌套,也就是MainLmmIndex中有TradeType屬性對應的對象,而TradeType中又有MainLmmIndex的Set對應的數組,循環嵌套,導致JSON數據越來越多,而被截斷了。

問題總結分析

綜上所述,問題原因如下:
1. TradeType與MainLmmIndex是雙向映射的;
2. 接口請求的是某TradeType下的MainLmmIndex的集合;
3. Controller的返回結果是Java類對象集合Set;
4. SpringMVC做轉換的時候,會把Java類對象轉換爲JSON,而MainLmmIndex的JSON數據中包含TradeType的信息,TradeType的JSON數據中包含MainLmmIndex的信息,這樣在轉換的時候就會循環嵌套,造成響應信息無限膨脹;
5. 其實服務器端已經報出了異常信息,但是最開始定位問題的時候沒有關注到對應的消息窗口(包含Debugger、Server、Tomcat Catalina Log、Tomcat Localhost Log,如下所示);
這裏寫圖片描述
6. 由於Server和Debugger,以及第一個Tomcat的輸出窗口都沒有輸出錯誤信息,所以忽略掉了;需要關注一下IDEA的這四個輸出窗口分別是在什麼時候用的!!

解決方案

雙向映射是必須的,因爲Service層有不少的業務邏輯需要使用雙向映射來簡化邏輯和提升效率。而且不能因爲自身出的問題怪罪到框架的頭上,所以解決方案是使用替代接口:自組JSON結構。

@Transactional(readOnly = true)
    public String getMainLmmIndexTree(String tradeTypeId) {
        List<MainLmmIndex> indexList = mainLmmIndexRepository.getRootMainLmmIndexByTradeTypeId(tradeTypeId);
        JSONArray indexArray = new JSONArray();
        for (MainLmmIndex index : indexList) {
            JSONObject indexObject = index.toJSONObject();
            Set<MainLmmIndex> childIndexSet = index.getChildIndexSet();
            for (MainLmmIndex childIndex : childIndexSet) {
                JSONObject childIndexObject = childIndex.toJSONObject();
                indexObject.getJSONArray("children").add(childIndexObject);
            }
            indexArray.add(indexObject);
        }
        return indexArray.toString();
    }

後記

Debugger窗口是Debugger的調試工具箱窗口,輸出Frames和Threads相關信息;另外也可以監視一些Variables;
Server窗口是程序日誌打印窗口,System.out以及日誌框架打印的一些日誌應該都會在這個窗口輸出;
Tomcat Catalina Log窗口是Tomcat的輸出窗口,主要輸出Tomcat本身的一些啓動信息之類的內容;
Tomcat Localhost Log窗口會輸出請求響應過程中的一些異常信息,對於程序調試有很大的作用。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章