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 getMainLmmIndexSet() {
        return mainLmmIndexSet;
    }

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

之前的接口运行得挺好,做了这个修改以后就出了问题,改回为单向映射之后,问题消失。

查看Controller接口

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

这个地方,Controller的返回类型为Set,这个Set是直接从映射关系中得到的,返回给前端的时候经过SpringMVC的类型转换成为JSON字符串(通过@RestController实现)。
那么这样做能看出什么问题呢?
好像有点循环……

Fiddler查看真实响应内容

Net::ERR_INCOMPLETE_CHUNKED_ENCODING问题跟踪_第1张图片
由于firebug仅仅能看到一个错误提示,从返回值的responseText看的时候为空,所以这里得不到什么有效的信息了。
由于网上有人提到说这个是由于Chrome导致的,所以尝试使用fiddler模拟一下请求。
使用Fiddler请求之后,在查看响应时弹出一个错误框:
Net::ERR_INCOMPLETE_CHUNKED_ENCODING问题跟踪_第2张图片
这说明不是Chrome的问题,而是接口自身的问题。
既然不能查看JSON格式的响应结果,看一下Raw格式的响应结果,发现了问题所在:
Net::ERR_INCOMPLETE_CHUNKED_ENCODING问题跟踪_第3张图片
这个还不是响应得全貌,水平滚动条仅仅占了全部内容的百分之五左右。
这个与预期的响应结果极为不符,因为查看数据库后得知对应的数据仅仅五六条而已,每条记录四五个字段,字符数也不多,不应该有如此之多的响应内容。
仔细查看后发现:
相应的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,如下所示);
Net::ERR_INCOMPLETE_CHUNKED_ENCODING问题跟踪_第4张图片
6. 由于Server和Debugger,以及第一个Tomcat的输出窗口都没有输出错误信息,所以忽略掉了;需要关注一下IDEA的这四个输出窗口分别是在什么时候用的!!

解决方案

双向映射是必须的,因为Service层有不少的业务逻辑需要使用双向映射来简化逻辑和提升效率。而且不能因为自身出的问题怪罪到框架的头上,所以解决方案是使用替代接口:自组JSON结构。

@Transactional(readOnly = true)
    public String getMainLmmIndexTree(String tradeTypeId) {
        List indexList = mainLmmIndexRepository.getRootMainLmmIndexByTradeTypeId(tradeTypeId);
        JSONArray indexArray = new JSONArray();
        for (MainLmmIndex index : indexList) {
            JSONObject indexObject = index.toJSONObject();
            Set 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窗口会输出请求响应过程中的一些异常信息,对于程序调试有很大的作用。

你可能感兴趣的:(hibernate,SpringMVC)