“不敢去怀疑代码,又不得不怀疑代码”记一次网络请求超时分析
摘要:此次定位,颇为复杂,而且有时让人没有思路,因为同一个接口,换一个环境又好使了,又不敢去怀疑代码;然而有问题的环境,换一个接口也好使了,又不得不怀疑代码
本文分享自华为云社区《一次网络请求超时分析》,作者:xiewenci 。
问题现象
发起http请求,后端服务接口/v5/iot/11c9c88e6fb26bead43b75514dc380eb/routing-rule/rules?limit=10&marker=ffffffffffffffffffffffff&offset=0,一直等待,一分钟后返回响应,且中文乱码显示
分析过程
1.首先定界,在正常环境和异常环境换一样的版本代码,测试同样接口,但是正常环境正常,异常环境还是等待1分钟,所以觉得是环境问题,于是下一步,抓包
2.分别再异常环境和正常环境抓包,具体流信息见下图:
异常环境的流信息
![](https://pic2.zhimg.com/80/v2-fa20cafe5b922254ae4379ccbc961191_720w.jpg)
正常环境的流信息
![](https://pic4.zhimg.com/80/v2-16e4bf98254527fb0f3a6341149fadb7_720w.jpg)
从图中看出正常环境是,服务端发送响应完成之后,由客户端正常返回ACK,然后由客户端发起FIN断链请求。而异常环境则是服务端发送响应完成之后,客户端也回了ACK,但是没有主动发起断链请求,直到超过keep-alive时间之后,由服务端发起了断链请求(因为超时主动断链)。现象是客户端一直在等服务端发送响应(可能没有发送完),所以怀疑服务端有缓存之类,没有及时将响应流发送出去,所以继续查看代码
3.查看代码,在返回客户端的时候,没有flush和close操作,代码如下
![](https://pic1.zhimg.com/80/v2-480c248ddf7a9ee2dca78c8e66275f38_720w.jpg)
然后以为找到问题原因所在了,就尝试修改代码,如下:
![](https://pic3.zhimg.com/80/v2-d89eee9deec8cb2f06674fce10e87312_720w.jpg)
增加了flush操作和close操作(放在了try语快中),最后测试执行,还是跟最初的现象一致,还是会等待1分钟后才会返回响应。这时就有点纳闷了,再重新仔细分析下流,其实从流中可以看出来,服务端的响应是立马返回给了客户端的,如下图
![](https://pic4.zhimg.com/80/v2-9038c61f5a1c3421bd241d04b8763cc7_720w.jpg)
既然给了响应,那为什么客户端为什么还要继续等待呢?这里有注意到图中有几个问号,这其实是中文字符乱码了,所以这里又怀疑是不是编码格式导致客户端收到的Content-Length长度和收到的响应的长度不一致,也就是客户端实际收到的响应的长度小于Content-Length的长度,然后一直等待下去,所以继续修改代码
4.修改代码,指定编码格式为UTF-8,代码如下:
![](https://pic4.zhimg.com/80/v2-bd188146348c2a0f3960159d6ae8caa7_720w.jpg)
替换环境版本,测试执行,响应就立马返回了,果然是这个编码格式的锅
原因回顾
1.编码格式不一致就会导致响应流的实际长度不一致?答案是一定的,编码格式不一致,实际长度就是会不一致,测试结果如下:
![](https://pic1.zhimg.com/80/v2-6c1be00a468942f1a638f9c05dc9e354_720w.jpg)
2.为什么之前的没有出现过这个问题?是什么原因导致编码格式丢失的
查看后端服务jar包,发现spring版本已经升级到5.2.21.RELEASE,此版本中没有指定默认编码格式为UTF-8
![](https://pic4.zhimg.com/80/v2-bd0b542a22fc89aea8d830a7fcec11f3_720w.jpg)
所以需要后端服务去指定编码格式,或者网关服务统一处理
总结与思考
此次定位,颇为复杂,而且有时让人没有思路,因为同一个接口,换一个环境又好使了,又不敢去怀疑代码;然而有问题的环境,换一个接口也好使了,又不得不怀疑代码;还有就是在容器中去调用接口,也是一样的问题,所以感觉又跟网络没啥关系。其实应该静下心来去思考为什么客户端那里一直等待,没有主动发起断链,这里还是说明了对HTTP协议细节,不够熟练掌握,才导致中间走了一些误区,需要去巩固和加深对http协议的理解。
相关文章
- Lua学习笔记
- 盛最多水的容器
- Java开发桌面程序学习(10)——css样式表使用以及Button使用
- AD 域登录验证
- Java开发桌面程序学习(九)——JavaFxTemplate JavaFx模版 更简单进行JavaFx程序开发
- 采用 Kettle 分页处理大数据量抽取任务
- Visual Studio开发Cordova应用示例
- Oracle Flashback 和 RMAN 示例
- 源代码管理的一些问题
- Java开发桌面程序学习(八)——启动浏览器或者打开资源管理器操作与hyperlink超链接的使用
- 不同种类软件的比较
- Java开发桌面程序学习(七)——ImageView设置图片以及jar包读取fxml文件
- Java开发桌面程序学习(六)——拖动文件获得文件路径
- Java开发桌面程序学习(五)——文件选择器和目录选择器的使用
- Visual Studio Code初探
- Java开发桌面程序学习(四)——常用应用布局模板和简单分析
- 过早的优化是万恶之源
- Java开发桌面程序学习(三)——基于Jfoenix库的JFXDialog封装仿Android对话框的工具DialogBuilder
- 关于阅读书籍的一点点感悟
- Java开发桌面程序学习(二)————fxml布局与控件学习