当前位置: 首页 > 知识库问答 >
问题:

Apache HttpClient有时会抛出超时异常

段干宏硕
2023-03-14

我的项目使用apache超文本传输协议html" target="_blank">客户端向超文本传输协议服务器发送超文本传输协议请求。但是奇怪的事情发生了。我设置连接超时为10秒,套接字超时为10秒。对于每一天,大多数请求时间(大约100个请求)是100ms-200ms,但是左(大约10个请求)将抛出连接超时异常,这意味着连接建立时间是10s以上。我不知道发生了什么。

我的电话是:

HttpUtils。post(主机,空,参数,“UTF-8”,1000010000)

下面是异常堆栈跟踪。

org.apache.http.conn.ConnectTimeoutException: Connect to ***.***.***.***:80 [] failed: connect timed out
    at org.apache.http.impl.conn.HttpClientConnectionOperator.connect(HttpClientConnectionOperator.java:134)
    at org.apache.http.impl.conn.PoolingHttpClientConnectionManager.connect(PoolingHttpClientConnectionManager.java:319)
    at org.apache.http.impl.execchain.MainClientExec.establishRoute(MainClientExec.java:363)
    at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:219)
    at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:195)
    at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:86)
    at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:108)
    at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:184)
    at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:82)
    at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:106)
    at HttpUtils.post(HttpUtils.java:201)



  Caused by: java.net.SocketTimeoutException: connect timed out
        at java.net.PlainSocketImpl.socketConnect(Native Method)
        at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:345)
        at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:206)
        at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:188)
        at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392)
        at java.net.Socket.connect(Socket.java:589)
        at org.apache.http.conn.socket.PlainConnectionSocketFactory.connectSocket(PlainConnectionSocketFactory.java:72)
        at org.apache.http.impl.conn.HttpClientConnectionOperator.connect(HttpClientConnectionOperator.java:125)
        ... 84 more

和我的超文本传输协议后客户端:

import java.io.IOException;
import java.nio.charset.Charset;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.net.ssl.SSLContext;

import org.apache.http.Consts;
import org.apache.http.HttpEntity;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.LayeredConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLContexts;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;



public class HttpUtils {

    private static final Logger logger = LoggerFactory.getLogger(HttpUtils.class);
    private static int SocketTimeout = 3000;// 3秒
    private static int ConnectTimeout = 3000;// 3秒
    private static Boolean SetTimeOut = true;

    public static CloseableHttpClient getHttpClient() {

        RegistryBuilder<ConnectionSocketFactory> registryBuilder = RegistryBuilder.<ConnectionSocketFactory> create();
        ConnectionSocketFactory plainSF = new PlainConnectionSocketFactory();
        registryBuilder.register("http", plainSF);
        try {
            KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
            TrustStrategy anyTrustStrategy = new TrustStrategy() {

                @Override
                public boolean isTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {

                    return true;
                }
            };
            SSLContext sslContext = SSLContexts.custom().useTLS().loadTrustMaterial(trustStore, anyTrustStrategy).build();
            LayeredConnectionSocketFactory sslSF = new SSLConnectionSocketFactory(sslContext, SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
            registryBuilder.register("https", sslSF);
        } catch (KeyStoreException e) {
            throw new RuntimeException(e);
        } catch (KeyManagementException e) {
            throw new RuntimeException(e);
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException(e);
        }
        Registry<ConnectionSocketFactory> registry = registryBuilder.build();
        PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(registry);
        HttpClientBuilder hcb = HttpClientBuilder.create();
        return hcb.setConnectionManager(connManager).build();
    }

    public static String get(String url, Map<String,String> queries) throws IOException {

        String responseBody = "";
        // CloseableHttpClient httpClient=HttpClients.createDefault();
        CloseableHttpClient httpClient = getHttpClient();

        StringBuilder sb = new StringBuilder(url);

        if (queries != null && queries.keySet().size() > 0) {
            boolean firstFlag = true;
            Iterator<Map.Entry<String,String>> iterator = queries.entrySet().iterator();
            while (iterator.hasNext()) {
                Map.Entry<String,String> entry = (Map.Entry<String,String>) iterator.next();
                if (firstFlag) {
                    sb.append("?" + (String) entry.getKey() + "=" + (String) entry.getValue());
                    firstFlag = false;
                } else {
                    sb.append("&" + (String) entry.getKey() + "=" + (String) entry.getValue());
                }
            }
        }

        HttpGet httpGet = new HttpGet(sb.toString());
        if (SetTimeOut) {
            RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(SocketTimeout).setConnectTimeout(ConnectTimeout).build();
            httpGet.setConfig(requestConfig);
        }
        try {
            CloseableHttpResponse response = httpClient.execute(httpGet);
            int status = response.getStatusLine().getStatusCode();
            if (status == HttpStatus.SC_OK) {
                HttpEntity entity = response.getEntity();
                // do something useful with the response body
                // and ensure it is fully consumed
                responseBody = EntityUtils.toString(entity);
                // EntityUtils.consume(entity);
            } else {
                System.out.println("http return status error:" + status);
                throw new ClientProtocolException("Unexpected response status: " + status);
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        } finally {
            httpClient.close();
        }
        return responseBody;
    }

    public static String post(String url, Map<String,String> queries, Map<String,String> params, String chatset,int socketTimeout,int connectTimeout) throws IOException {

        String responseBody = "";
        CloseableHttpClient httpClient = getHttpClient();
        StringBuilder sb = new StringBuilder(url);

        if (queries != null && queries.keySet().size() > 0) {
            boolean firstFlag = true;
            Iterator<Map.Entry<String,String>> iterator = queries.entrySet().iterator();
            while (iterator.hasNext()) {
                Map.Entry<String,String> entry = (Map.Entry<String,String>) iterator.next();
                if (firstFlag) {
                    sb.append("?" + (String) entry.getKey() + "=" + (String) entry.getValue());
                    firstFlag = false;
                } else {
                    sb.append("&" + (String) entry.getKey() + "=" + (String) entry.getValue());
                }
            }
        }

        // 指定url,和http方式
        HttpPost httpPost = new HttpPost(sb.toString());
        if (SetTimeOut) {
            RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(socketTimeout).setConnectTimeout(connectTimeout).build();
            httpPost.setConfig(requestConfig);
        }
        List<NameValuePair> nvps = new ArrayList<NameValuePair>();
        if (params != null && params.keySet().size() > 0) {
            Iterator<Map.Entry<String,String>> iterator = params.entrySet().iterator();
            while (iterator.hasNext()) {
                Map.Entry<String,String> entry = (Map.Entry<String,String>) iterator.next();
                nvps.add(new BasicNameValuePair((String) entry.getKey(), (String) entry.getValue()));
            }
        }
        // Consts.UTF_8
        httpPost.setEntity(new UrlEncodedFormEntity(nvps, chatset));

        CloseableHttpResponse response = httpClient.execute(httpPost);
        try {
            if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
                HttpEntity entity = response.getEntity();
                // do something useful with the response body
                // and ensure it is fully consumed
                responseBody = EntityUtils.toString(entity);
                // EntityUtils.consume(entity);
            } else {
                System.out.println("http return status error:" + response.getStatusLine().getStatusCode());
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            response.close();
        }
        return responseBody;
    }



    public static String post(String url, Map<String,String> queries, Map<String,String> params, String chatset) throws IOException {
       return   post( url, queries, params,chatset,SocketTimeout,ConnectTimeout);
    }


}

从堆栈跟踪中,我们可以看到超时发生在连接建立期间,而不是数据传输期间。我想详细的原因在于其中一个:

1.正在等待池中的可用连接线程

2.无法连接到远程主机。

谁能给我一些建议?

共有1个答案

虞华翰
2023-03-14

您可以增加连接池日志记录位置org。阿帕奇。http。impl。连接=调试https://hc.apache.org/httpcomponents-client-ga/logging.html所以,当异常发生时,您将看到池中有多少打开的连接。异常显示HttpClient尝试建立新连接,这意味着打开的连接少于池大小。

>

  • 由于以下原因,客户端无法连接到远程主机:

    • 网络问题

    这意味着池中没有活动连接。然后,您需要嗅探网络流量,以找出问题所在,正如dave_thompson_085所建议的那样。

    某些防火墙/防病毒程序正在阻止客户端与服务器的连接,在这种情况下,池中可能存在连接。(如果这是请求服务器的唯一进程)

  •  类似资料:
    • 我在其中一个POJO中使用javax.validation.constraints.NotNull,如下所示: 然后,即使我为两个字段都使用 null 值制作 Abc 的对象,它也不会引发任何异常。知道为什么吗? 例如。 不会抛出任何异常。

    • 抛出异常的行为是否可能抛出不同的异常? 为了抛出异常,必须(可选地)分配新对象,并调用其构造函数(隐式调用fillinstacktrace)。在某些情况下,听起来像addSupressed也被称为。那么如果没有足够的内存会发生什么呢?JVM是否需要预分配内置异常?例如,(1/0)会抛出OutOfMemoryError而不是ArithmeticException吗? 此外,构造函数是一个方法调用,因

    • 我的Java代码使用共享的ApacheHttpClient 4.4。1.我将每个POST请求级别上的连接超时、套接字超时和连接请求超时设置为100毫秒。它大部分时间都很好用。然而,在大量请求(压力测试)时,HttpClient忽略这些超时;请求可能需要20秒或更长时间。这是我的密码: 在某些情况下,我会得到如下日志记录: 2018-10-26 14:18:45496[my-thread-1]调试c

    • 我注意到,在这个javadoc中,https://docs.oracle.com/javase/7/docs/api/java/lang/Thread.UncaughtExceptionHandler.htmlUncaughtExceptionHandler用于发生异常但未被捕获的情况。但是,那个线程会悄悄地失败吗?我想是的,因为它是异步进行业务的,但我正在调查我们的一个进程的相关问题,我很惊讶现

    • 问题内容: 我正在尝试从服务器中获取数据。有时我的代码由于导致失败。这是为什么?这个问题是什么原因造成的? 问题答案: 如果在DNS服务器中发生了打cup,则可能会发生这种情况。除了使DNS服务器更强大或寻找另一台服务器之外,您还可以使用完整的IP地址代替主机名。这样,就无需根据主机名查找IP地址。但是,我宁愿解决DNS问题,也更喜欢DNS,因为IP地址可能会不时更改。

    • 我使用的是SpringBoot2.2。2.发布,version 在 超时失败统计(总计=30,活动=1,空闲=29,等待=163) 有29个空闲连接,仍然发生超时故障。