u012730827
z永不言弃y
2019-01-25 14:01

httpclient-4.5.2读取超时,重发没起到作用,为什么?

  • java
  • java-ee
  • eclipse

1、写了一个httpclient的工具类,也写了重试的逻辑,
但是在多个线程在使用同一个httpclient实例的时候,
发现线程read time out的超时并没有被重发很郁闷(线程直接进入的SocketTimeoutException异常,
导致本次线程的请求没有拿到再次重发后的结果,导致数据丢失)

public CloseableHttpClient getHttpClient() {


    return HttpClients.custom().
            setConnectionManager(connMrg).
            setKeepAliveStrategy(myStrategy).
            setDefaultRequestConfig(requestConfig).
            setConnectionManagerShared(true).
            setMaxConnTotal(maxTotal).
            setRetryHandler(
                    new HttpRequestRetryHandler() {

                        @Override
                        public boolean retryRequest(IOException exception , int executionCount , HttpContext context) {
                            // 重试3次,从3开始
                            if (executionCount > 3) {
                              return false;
                            }
                            /*
                            if (exception instanceof NoHttpResponseException) {
                                System.out.println(
                                  "[NoHttpResponseException has retry request:" + context.toString() + "][executionCount:" + executionCount + "]");
                              return true;
                            }
                            else if (exception instanceof SocketException || exception instanceof ConnectTimeoutException || exception instanceof SocketTimeoutException  ) {
                                System.out.println("[SocketException has retry request:" + context.toString() + "][executionCount:" + executionCount + "]");
                              return true;
                            }
                            */
                            if (exception instanceof UnknownHostException) {
                                return false;
                            }
                            // SSL handshake exception
                            if (exception instanceof SSLException) {
                                return false;
                            }
                            //除上述两种异常其他异常均重试3次,其实主要问题在于
                            //服务端对连接数限制,会导致你再怎么重试,都会异常,连接数满了,重试还有毛用
                            //所以设置连接池的时候需要设置的比他们的最大值小,用完要及时释放到连接池
                            String time3 = new SimpleDateFormat("HH:mm:ss.SSS").format(new Date());
                            System.out.println("time:"+time3+"="+Thread.currentThread().getName() +"\n"+"[Exception:"+exception.toString()+" has retry request:" + context.toString() + "][executionCount:" + executionCount + "]");
                            return true;
                        }

                        }

                    ).

            build();

}
    问题3:  String time3 = new SimpleDateFormat("HH:mm:ss.SSS").format(new Date());
                            System.out.println("time:"+time3+"="+Thread.currentThread().getName() +"\n"+"[Exception:"+exception.toString()+" has retry request:" + context.toString() + "][executionCount:" + executionCount + "]");
                            return true;

这段代码发生read time out的时候执行了,但是executionCount一直都是1,我理解应该是重发了一次,但是子线程里的日志打印了异常,并没有获取到重试后的结果

问题4,子线程取数据逻辑,只写了主要逻辑
httpPost.setHeader("Content-Type", "text/xml;charset=UTF-8");
// httpPost.setHeader("SOAPAction", "");
StringEntity data = new StringEntity(inputPara, Charset.forName("UTF-8"));
httpPost.setEntity(data);

        try {
            response = httpClient.execute(httpPost);
            httpEntity = response.getEntity();
            if (httpEntity != null) {
                // 获取响应内容
                returnVal = EntityUtils.toString(httpEntity, "UTF-8");
                // 消费掉节约内存,并关闭inputstream流
                EntityUtils.consume(httpEntity);

                }
                } catch (Exception e) {
                        e.printStackTrace();

                }
                finally {
            try {
                // 关闭流并释放资源
                response.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        我认为在这段的httpEntity = response.getEntity();执行的时候
        readtime out,然后代码直接进入了catch逻辑,所以重发后的结果并没有取到。

问题5:
1、我就是想解决,读取超时就重发,一直到3次结束。
2、是不是我设置的读取超时时间为60s导致根本没办法重发,服务端可能已经把短连接关闭了
因为http默认短连接时间好像就是60s。我猜测,如果我设置读取时间为10s,可能就可以重试3次了。

3、

try{
httpEntity = response.getEntity();
}
catch()
{
}
这段逻辑跟
创建httpclient的方法里面的重试方法,当发生异常时,到底是这段阻塞httpEntity = response.getEntity(); 等待3次重发?还是是异步的,里面重发,外面直接进入异常逻辑,根本不等重发后的结果

  • 点赞
  • 回答
  • 收藏
  • 复制链接分享

1条回答