1.问题描述:
并发大量同url同参的Http 请求下,okhttp 返回的response 打印其header正常,在打印其body体时,却抛出异常,如下图所示:
根据输出的日志,锁定关键日志ProtocolException 707 bytes but received 1065
, 协议异常了。
2.分析定位:
根据,ProtocolException 707 bytes but received 1065
和 content-length: 707
, 可知: 接受到一个content-length为707长度的http消息包,但真正body体的长度却是1065。
在okhttp(3.14.9版本中),检索关键,有两个点可能抛出该异常:
从源码可知,在Request 和Response 中,除开content-length为-1(未知长度)外,当其和body长度对不上都可以抛出该异常。
常见的原因可能有两种:
- 使用了string 字符的长度,没有使用byte的长度作为content-length , 中英文的字符所占字节数不一样导致;
- content-length 填写有误,存在重组包或者body体严重超长导致;
为了探究根本原因,必须将body打印出来,判断是request 有问题还是response有问题,占对比body中长度问题。
1.通过Studio 的断点功能来调试:
通过断点,抛出异常的源码,锁定发现是response 的body 读取异常导致;
接下来,为了再次更方便复现,直接通过read==1065
条件断点,锁定抛出异常的情况:
当进程断点成功后,将read 修改其值为707,让其body能够完整打印出来。
最终,经过两步骤,可以得到完整的body内容:
从上可知,body 内容除开正常内容外,还将header的内容也写进body了,也即难怪会多出几个字节。
将完整的body字符,再通过计算字符字节数进行验证:
附带,计算字节的网站:字数和字节数查询
2.通过抓包工具fiddler等,来抓包:
对于调试不熟悉的小伙伴,也可以考虑抓包来获取。更多fiddler抓包,详情阅读(Android APP)HTTP调试代理之Fiddler抓包
重现该异常情况,抓包数据如下所示:
也是一样,可以正常获取body内容。
3.解决方案
对于,该案例所遇到的异常情况,必须由服务端童鞋解决,查清楚从服务器到网关到socket过程中,哪个环节重组包发生错误,导致包体错乱。
对于,其他情况正常数据返回,可以考虑将content-length 设置为-1便可解决。