关于HTTP客户端重复发送请求的问题

来源:互联网 发布:简易电路设计软件 编辑:程序博客网 时间:2024/05/17 06:15

     关于HTTP客户端重复发送请求的问题

问题描述:在进行HTTP接口联调的过程中发现的问题,外围厂商HTTP服务端查看日志发现,客户端有重复发送请求的情况。

 

经过一些列的查询、学习、追踪,及大家的帮助最终确认了问题原因,并成功解决。写出来与大家分享。如果有遇到类似问题的朋友路过,希望有借鉴意义。

首先检查客户端程序是否有重复发送的可能,核对程序源码及接口日志发现客户端并没有重复发送请求的情况。

通过反复测试,发现只有在连续发送客户端请求的情况下,服务端才会反映,他们收到客户端发送重复请求的情况。

刚开始也怀疑服务端程序是否在处理过程中出现了问题。

服务端也确认他们程序没有问题。

双方都没有进展,我想到用抓包工具来抓包看看。也想以此来证明我们就发送了一次。

通过抓包工具发现客户端的确发送了两次请求的情况。我慌张了,难道真是我们的问题?

抓包工具:tcpdump

主机:UNIX

先确认tcpdump需要监听的接口,通过netstat -in

抓包命令:tcpdump -f -vv -A  -i lan1 host 192.168.*.* and port 14000

-A  ASCII码方式显示每一个数据包。

-i  指定tcpdump需要监听的接口。

-v  当分析和打印的时候,产生详细的输出。

-vv 产生比-v更详细的输出。

host 监视指定主机的数据包。

port 监视指定端口的数据包。

我们的客户端的确有重发机制,但那是针对超时(配置设置3秒)的情况下才会触发一次重传,后来修改代码,把这块重传机制也删除掉,继续测试,还是不行,抓包还有重复请求发送。这真是到了“乱用药”阶段了,确认不了原因,就盲目尝试希望可以解决。

就在很纠结的时候,想到了以前看过tcp协议,面向连接的、可靠的协议。有重发的可能。

由于不在单位连不上主机,自己在WIN7系统上通过wireshark抓包,写了模拟测试程序,发现了些端倪。

模拟客服端程序连续发送请求的时候,只进行一次tcp连接即三次握手,所有请求都结束了才会断开连接即四次挥手。

在网上查了一下是由于keep-alive的原因。

HTTP协议采用请求-应答模式,当使用普通模式,即非KeepAlive模式时,每个请求/应答客户和服务器都要新建一个连接,完成之后立即断开连接(HTTP协议为无连接的协议);当使用Keep-Alive模式(又称持久连接、连接重用)时,Keep-Alive功能使客户端到服务器端的连接持续有效,当出现对服务器的后继请求时,Keep-Alive功能避免了建立或者重新建立连接。

http 1.0中默认是关闭的,需要在http头加入"Connection: Keep-Alive",才能启用Keep-Alivehttp 1.1中默认启用Keep-Alive,如果加入"Connection: close ",才关闭。目前大部分浏览器都是用http1.1协议,也就是说默认都会发起Keep-Alive的连接请求了,所以是否能完成一个完整的Keep- Alive连接就看服务器设置情况。

将服务端http头加入"Connection: close ",再次进行测试并抓包。

 

根据分析基本上可以确认是服务端在keep-alive设置的问题。

再次在公司测试环境上进行抓包测试

在保持持续连接的情况下,再次向服务端发送请求时,结果服务端发送了Flags [R.]返回给客户端。

TCP层,FLAG字段,RST表示连接重置。服务端向客户端发送了连接重置请求,致使客户端重新进行了TCP连接,并重新发送了请求。

这就可以解释为什么服务端接收到客户端的两次请求报文。

问题原因:

服务端程序不支持keep-alive方式的处理方法,但在应答http头中没有说明”Connection: close”,客户端以为服务端支持这种方式处理,便持续发送请求,结果服务端发送了RST,导致客户端进行TCP重连并重新发送了请求。

解决方法:

1.服务端在报文头中增加”Connection: close”,便解决了此问题。

2.服务端修改代码,支持keep-alive方式处理。

3.客户端修改HTTP头,Connection:close。(此种方式并不合理)