【网络容灾失败案例】三种HTTP请求重试导致重复提交

golcm
发布于 2023-1-17 11:20
浏览
0收藏

使用一些类库进行http请求时,比如使用Apache HttpComponents 库。默认的, HttpClient 尝试自动从 I/O 异常恢复。这种自动恢复机制仅限于一些被认为是安全的异常,比如套接字被重置或者套接字被关闭。但是有些场景重试会造成重复请求风险。

一般来讲,重复请求比网络异常直接返回失败对用户是更差的体验。因为重复请求,实际造成了影响,但是给上游返回是成功,这样实际结果和给上游的返回结果不一致,自身系统从准确性上来说是不准确的。如果网络异常就返回失败,上游有自主处理的权利,某些场景他们可以自己发起重试,有些可以通过查询、核对等手段获取正确的结果。

以下三种场景重试会导致重复提交。

场景一:读超时 Read timeout

在发HTTP请求时,建立连接后:请求方会先进行请求数据写操作,对方才能收到请求;对方处理完成之后会返回结果,请求方要读取请求结果,这时候是读操作。

所以如果遇到网络数据读超时,会重复提交。

场景二:套接字异常 Unexpected end of file from server

这个异常说明数据已经发送成功。有可能服务端是防火墙的原因,没有处理客户端发来的数据。也有可能是客户端的数据不符合要求,服务端没有做出响应。数据不符合要求可能是传送的数据含有奇怪的字符。也有可能是两边编码不一致导致。客户端将字符串变成字节数据传送时需要指定编码格式,如str.getBytes(“UTF-8”);如不指定,可能导致上面的错误。当URL过长时也会发生此错误。

返回数据为空或者499的HTTP状态码与上面情况产生原因类似,也很有可能数据已经发送成功,重试需谨慎。

场景三:连接被重置

在Java的httpClient组件中,默认是会对套接字被重置做重试的。可是我就实际遇到过套接字被重置,实际上是数据已经发送成功的场景。详见:《connection reset案例的穿越之旅》。简而言之,就是A调用B,B系统前面有一层网络设备。实际上A是和B的网络设备建立长连接。一旦B系统出现错误抛出异常,前面那层网络设备作为客户端感知到了B系统的异常,主动断开连接关闭了自己与A系统的异常。A得到的结果就是连接被重置。所以httpClient等常用组件的默认重试策略也并不可靠。


文章转载自公众号:编程一生


分类
标签
已于2023-1-17 11:20:47修改
收藏
回复
举报
回复
    相关推荐