关于httpclient 连接失效引发的问题

 一 排查过程

使用的httpclient客户端,版本是:

<dependency>
        <groupId>org.apache.httpcomponents</groupId>
        <artifactId>httpclient</artifactId>
        <version>4.3.2</version>
</dependency>

在生产环境发现有时会报错:

org.apache.http.NoHttpResponseException: The target server failed to respond

怀疑是Nginx超时之后连接不可用,但是连接池里面没有剔除导致,为了简化排错,在本地直接设置了一个线程循环跑,把sleep时间调整成Nginx超时时间5s,代码如下:

DefaultHttpClient httpClient = new DefaultHttpClient();
        httpClient.setHttpRequestRetryHandler(new DefaultHttpRequestRetryHandler(0, false));
        HttpGet httpGet = new HttpGet("http://192.168.31.176/index_10s.html");
        httpGet.addHeader("User-Agent", USER_AGENT);
        CloseableHttpResponse httpResponse = null;
        for (int i = 0; i < 100; i++)
            try {
                httpResponse = httpClient.execute(httpGet);
                System.out.println("GET Response Status:: "
                        + httpResponse.getStatusLine().getStatusCode());
                BufferedReader reader = null;
                reader = new BufferedReader(new InputStreamReader(
                        httpResponse.getEntity().getContent()));
                String inputLine;
                StringBuffer response = new StringBuffer();
                while ((inputLine = reader.readLine()) != null) {
                    response.append(inputLine);
                }
                Thread.sleep(5000);
            } catch (IOException e) {
                e.printStackTrace();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

这里把httpclient设置成了不重试的机制。在跑了之后,发现确实出现了NoHttpResponseException报错。
把当时的包抓下来,看到如下所示:
image

  1. 首先是三次建联过程;
  2. 中间两个get都成功,注意相差了5s,这是Nginx的keepalive时间;
  3. 下面是关键过程:
    image
    我们看到,
    (1)在首个包发送完成之后5s,已经到达Nginx的keepalive时间,此时服务端主动断开连接,发送了FIN包(注意这里的客户端服务端是指的现在192是客户端(发起http请求的一方),服务端指的是176(Nginx))。
    (2)客户端响应服务端请求,发送ACK包,此时192处于CLOSE_WAIT状态,176处于FIN_WAIT2状态,此时192仍然可以向176发送数据,但是176不会再向192发送数据,但是仍人可以接收192的数据;
    (3)这时候我们发现,192向176发送了get请求,这个请求自然就被rst了;

 二 httpclient使用

通常我们在使用的时候,不会考虑是否需要设置retry,实际上设置retry为false是非常重要的,在涉及到一致性的请求中,如果一次请求失败之后重新尝试,那中间会发生什么问题是未知的(代码返回失败!=请求失败)

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值