HttpClient踩坑记录

HttpClient踩坑记录

在最近做的一个项目中,有一个定时任务经常卡死不动,经过查看log排查发现罪魁祸首在这

HttpResponse response = HttpUtil.getHttpClient().execute(post);

程序运行到这里就就不动了,进去getHttpClient()方法查看:


public class HttpUtil
{

    private static HttpClient httpclient = null;
    private static HttpClient httpsclient = null;
    private static final Logger logger = Logger.getLogger(HttpUtil.class);

    static
    {
        RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(48000).setSocketTimeout(30000).build();
        httpsclient = HttpClients.custom().setDefaultRequestConfig(requestConfig).build();
        httpclient = getSSLHttpClient();
    }
    public static HttpClient getHttpClient()
    {
        return httpclient;
    } 

可以看出这是个单例模式,共用一个HttpClient,http底层协议是基于tcp的,最终实现是通过socket,socket中有两个超时时间,一个是连接超时时间connectTimeout,另一个是连接成功后,多长时间数据没有返回断开连接soTimeOut。接着看getSSLHttpClient()方法中有没有设置超时时间

    private static CloseableHttpClient getSSLHttpClient()
    {
        try
        {
            SSLContext context = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy()
            {

                @Override
                public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException
                {
                    return true;
                }
            }).build();

            SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(context);
            RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(48000).setSocketTimeout(30000)
                    .build();
            return HttpClients.custom().setSSLSocketFactory(sslsf).setDefaultRequestConfig(requestConfig).build();
        }
        catch (KeyManagementException e)
        {
            logger.error("ssl context key management Exception {}", e);
            throw new RuntimeException("ssl context key management Exception", e);
        }
        catch (NoSuchAlgorithmException e)
        {
            logger.error("ssl context get instance faild, no such method {}", e);
            throw new RuntimeException("ssl context get instance faild", e);
        }
        catch (KeyStoreException e)
        {
            logger.error("ssl context key store Exception {}", e);
            throw new RuntimeException("ssl context key store Exception", e);
        }
    }

从代码中可以看到是有设置超时时间的,这是为什么呢,搞不懂只好百度,发现发现虽然在RequestConfig设置了SocketTimeout,但在最底层设置SoTimeout时并未使用,socket中如果不设置该值则会导致socket连接成功后如果不返回数据,则该socket会一直等待。
既然在RequestConfig中设置无效,那只好在SocketConfig中设置了,加上如下代码即可解决:

SocketConfig socketConfig = SocketConfig.custom().setSoTimeout(20000).build();
HttpClients.custom().setSSLSocketFactory(sslsf) .setDefaultSocketConfig(socketConfig).setDefaultRequestConfig(requestConfig).build();

最终getSSLHttpClient()方法改为如下:

    private static CloseableHttpClient getSSLHttpClient()
    {
        try
        {
            SSLContext context = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy()
            {

                @Override
                public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException
                {
                    return true;
                }
            }).build();

            SocketConfig socketConfig = SocketConfig.custom().setSoTimeout(20000).build();
            SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(context);
            RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(48000).setSocketTimeout(30000)
                    .build();
            return HttpClients.custom().setDefaultSocketConfig(socketConfig).setSSLSocketFactory(sslsf)
                    .setDefaultRequestConfig(requestConfig).build();
        }
        catch (KeyManagementException e)
        {
            logger.error("ssl context key management Exception {}", e);
            throw new RuntimeException("ssl context key management Exception", e);
        }
        catch (NoSuchAlgorithmException e)
        {
            logger.error("ssl context get instance faild, no such method {}", e);
            throw new RuntimeException("ssl context get instance faild", e);
        }
        catch (KeyStoreException e)
        {
            logger.error("ssl context key store Exception {}", e);
            throw new RuntimeException("ssl context key store Exception", e);
        }
    }
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值