netty解析http协议异常Connection closed before received headers 分析

背景:

今天巡检公司的网关服务器错误日志时发现有少量的http协议解析PrematureChannelClosureException:Connection closed before received headers错误,记录下整个查找异常原因的过程

错误追踪:

首先我们的网关服务器是使用Netty实现的,使用HttpObjectDecoder/HttpObjectEecoder作为对应的http协议的编解码器,错误日志如下:netty解析http协议异常Connection closed before received headers 分析_第1张图片

从错误信息可知,关闭连接的时候去检查http协议的解析状态发现协议未解析完整而导致的报错,那么问题就变成了既然http协议都没有解析完,那么谁会关闭连接呢?

问题1:是服务端关闭连接还是客户端关闭的连接?
正常来说,服务端只有在连接空闲超过一定时间的时候才会发送Fin请求关闭连接,这种情况一般来说很少发生,不过也不能排除,于是只有使用wireshark抓包了,抓包的结果证实了请求关闭连接的包是从客户端发送的,这就让人疑惑了,为什么有些客户端在http协议都没有发送完,也就是比如http协议包需要两个tcp包,客户端仅仅只发送了第一个tcp包后就关闭了连接,这里到目前为止还是不知道为什么有些客户端会有这么奇怪的行为。不过这里至少可以确认确实有些http客户端在发送了不完整的http请求之后马上发送FIN/RST请求关闭连接,在测试环境使用Jemter模拟这种请求,也就是发送一个不完整的http请求包,然后马上发送FIN/RST可以复现一样的错误日志

问题2:使用FIN和RST关闭连接有差异吗?
使用FIN关闭连接会经历完整的四次连接挥手阶段,并且客户端的端口需要经历time_wait的状态,而使用RST关闭连接时,连接会重置,客户端端口不需要经历time_wait状态,可以马上复用,不过马上复用端口其实是有风险的,具体这里不展开了,
备注:在java里面使用Channel.close关闭连接时,如果设置SO_LINGER=0 ,发送的就是RST包,如果SO_LINGER !=0 ,发送的就是FIN包,则会走tcp的四次挥手的流程

彩蛋: nginx是如何处理这种http解析不完整的情况的?
使用jemter模拟了一下之前的场景,把数据包发送到nginx服务器,发现ngnix服务器返回的是400 bad request错误.

你可能感兴趣的:(java,工具类,netty,http,网络,服务器)