《转》HttpURLConnection 自动重试机制
原文:https://blog.csdn.net/u010826617/article/details/90146170
问题描述:
对接某第三方聚合支付的反扫支付时,对方返回单号重复,导致收银失败。在业务层确认外部单号没有重复以及没有做失败重试处理后,怀疑是 http 客户端存在自动重试机制,于是往这个方面查可以确认是 HttpURLConnection 自动进行了请求重试。
原理分析:
HttpURLConnection 采用 Sun 私有的一个 HTTP 协议实现类: HttpClient.java
关键是下面这段发送请求、解析响应头的方法:
在第 600 – 614 行的代码里:
failedOnce 默认是 false,表示是否已经失败过一次了。这也就限制了最多发送 2 次请求。
httpuc 是请求相关的信息。
retryPostProp 默认是 true,可以通过命令行参数(-Dsun.net.http.retryPost=false)来指定值。
streaming:默认 false。 true if we are in streaming mode (fixed length or chunked) 。
通过 Linux 的命令 socat tcp4-listen:8080,fork,reuseaddr system:“sleep 1”!!stdout 建立一个只接收请求、不返回响应的 HTTP 服务器。
对于 POST 请求,第一次请求发送出去后解析响应会碰到流提前结束,这是个 SocketException: Unexpected end of file from server,parseHTTP 捕获后发现满足上面的条件就会进行重试。服务端就会收到第二个请求。
解决方案:
1、禁用 HttpURLConnection 的重试机制。
通过启动程序命令参数 -Dsun.net.http.retryPost=false
或代码设置 System.setProperty(“sun.net.http.retryPost”, “false”)
2、使用 Apache HttpComponents 库。
默认的, HttpClient 尝试自动从 I/O 异常恢复。这种自动恢复机制仅限于一些被认为是安全的异常。
HttpClient 不会尝试从任何逻辑或 HTTP 协议错误恢复;
HttpClient 会自动重试那些被认为是幂等的方法;
HttpClient 会自动重试那些仍在发送 HTTP 请求到目标服务器时出错的方法。(例如,请求还没有完整传输到服务器)。
3、服务端幂等性校验
其他问题:
关于 java.net.SocketException: Unexpected end of file from server
这个异常说明数据已经发送成功。有可能服务端是防火墙的原因,没有处理客户端发来的数据。也有可能是客户端的数据不符合要求,服务端没有做出响应。数据不符合要求可能是传送的数据含有奇怪的字符。也有可能是两边编码不一致导致。客户端将字符串变成字节数据传送时需要指定编码格式,如 str.getBytes(“UTF-8”);如不指定,可能导致上面的错误。另外有人说当 URL 过长时也会发生此错误,当使用 URL 发送数据时,可以参考此意见。
版权声明: 本文为 InfoQ 作者【hasWhere】的原创文章。
原文链接:【http://xie.infoq.cn/article/699fd7e3fd2c19545b7622e8f】。文章转载请联系作者。
评论