HttpClient 调用耗时长服务问题记录和处理方案

问题

  • java.net.SocketException: Connection reset

现象

  • 第一次请求,可能成功,可能失败,但是从第二次开始一直失败,隔断时间再次访问,可能成功,可能失败,连续请求的话都是失败

弯路

  1. 耗时接口的封装最大超时时间5s -> 30s,确保集团能够正常返回
  2. 某些平台超时3次后限制接口调用

httpclint的post方法

  • 改造前
    private String executePost(String url, String requestBody) throws Exception {
            String responseBody = "";
            PostMethod method = null;
            try {
                HttpClient client = new HttpClient();
                client.getParams().setParameter(HttpMethodParams.HTTP_CONTENT_CHARSET, "UTF-8");
                client.getHttpConnectionManager().getParams().setConnectionTimeout(10*1000);
                method = new PostMethod(url);
                method.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
                method.setRequestHeader("Cookie", "JSESSIONID=F3CC0575913DE1C788D8F000A5524FB3; 0yHmMQUi4f9KO=5AuDkrob9X6NMNHqy.laR8DNMYG.am6Y7vEDX17fj8OjIRUJ9eEAW2n0yWH7mnVlJCnnnXTgLuGAXeS9nr9N8Ea; WT_FPC=id=17dd3ad154dcb5557941647484475935; 5224c5f07e5da28b61=26eb640ae4a64f32311705753eb90f37; WT_SS=1652929249977765b8e56b; Hm_lvt_9004434f3a31031836fd6a07df4d1ae8=1652153360,1652254394,1652750419,1652929250; bjeshoptest=bjeshoptest; jsession_id_scsva=nB72A66AC6FF6C9137360E15C0D6CDAC5-1; WT_si_n=MM_ADV_HOME; 0yHmMQUi4f9KP=53LKuGKtmzE9qqqDqC9VaiaUuYLzaICp8Mo1GZ5Q1ZT3fvcQVY7aZ0feKR6onzWB_eY2XGuihtGEv_ZLZPzH2oVzEueSLsWI2y0YymbQbdil1fDgX0LO1paBZKcpQQ88M4ukGVybeTjeWGZCVpWZ_svEVMQV68Ut.fiZUEktEH23TzKsU_8iu4O4TV0TCfSj2d16pNEMSKXkLR7f7J5bInFPgLFRisEQ954egftQXAq9vZG.ilJEJTwdqrzg0vTQjOlOskOZjMR_hrN5saM0Lxe; Hm_lpvt_9004434f3a31031836fd6a07df4d1ae8=1652929673");
                method.getParams().setParameter(HttpMethodParams.HTTP_CONTENT_CHARSET, "UTF-8");
                InputStream input = new ByteArrayInputStream(requestBody.getBytes("UTF-8"));
                method.setRequestEntity(new InputStreamRequestEntity(input));
                int statusCode = client.executeMethod(method);
                if (HttpStatus.SC_OK == statusCode) {
                    byte[] bys = method.getResponseBody();
                    responseBody = new String(bys, "UTF-8");
                }
            } catch (Exception e) {
                throw e;
            } finally {
                if (method != null) method.releaseConnection();
            }
            return responseBody;
        }
    
  • 问题
    • 使用HttpClient都是使用类似上面的代码,因为Apache官方例子就是如此。但在使用HttpClient会发现如果不断循环发送大量请求到服务器会导致APACHE服务器的连接被占满,后续的请求便排队等待,程序陷入“假死”状态。
      1. Timeout 30
      2. KeepAlive On #表示服务器端不会主动关闭链接
      3. MaxKeepAliveRequests 100
      4. KeepAliveTimeout 180
    • 因此这样的配置就会导致每个链接至少要过180S才会被释放,这样在大量请求访问时就必然会造成连接被占满,请求等待的情况。在 通过DEBUG后发现HttpClient在method.releaseConnection()后并没有把连接关闭,这个方法只是将连接返回给 connection manager。如果使用HttpClient client = new HttpClient()实例化一个HttpClient connection manager默认实现是使用SimpleHttpConnectionManager。SimpleHttpConnectionManager有个构 造函数如下
      public SimpleHttpConnectionManager(boolean alwaysClose) {   
          super();   
          this.alwaysClose = alwaysClose;   
      } 
      

解决方案

  • 方法一:
    • 把事例代码中的第一行实例化代码改为如下即可,在method.releaseConnection();之后connection manager会关闭connection 。
      Java代码
      HttpClient client = new HttpClient(new HttpClientParams(),new SimpleHttpConnectionManager(true) );  
      
  • 方法二:

    • 实例化代码使用:HttpClient client = new HttpClient();在method.releaseConnection();之后加上
      Java代码
      ((SimpleHttpConnectionManager)client.getHttpConnectionManager()).shutdown();  
      shutdown源代码很简单,看了一目了然
      Java代码
      public void shutdown() {   
          httpConnection.close();   
      }  
      
  • 方法三:

    • 实例化代码使用:HttpClient client = new HttpClient();
      在method.releaseConnection();之后加上
      client.getHttpConnectionManager().closeIdleConnections(0);此方法源码代码如下:
      Java代码
      public void closeIdleConnections(long idleTimeout) {   
          long maxIdleTime = System.currentTimeMillis() - idleTimeout;   
          if (idleStartTime <= maxIdleTime) {   
              httpConnection.close();   
          }   
      }  
      将idleTimeout设为0可以确保链接被关闭。
      以上这三种方法都是有客户端主动关闭TCP链接的方法。下面再介绍由服务器端自动关闭链接的方法。
      
  • 方法四:
    • 代码实现很简单,所有代码就和最上面的事例代码一样。只需要在HttpMethod method = new GetMethod("http://www.apache.org");加上一行HTTP头的设置即可
      Java代码
      method.setRequestHeader("Connection", "close"); 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

乘风御浪云帆之上

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值