Apache HttpClient 超时时间区别与验证

概述

HttpClient 有 3 个超时时间设置,通过配置 RequestConfig 即可配置请求的超时时间,各个参数的作用如下:

  • connectTimeout:请求连接超时时间,超时会抛出 org.apache.http.conn.ConnectTimeoutException: Connect to 127.0.0.1:8083 [/127.0.0.1] failed: connect timed out异常。例如请求本地不存在的一个服务:http://127.0.0.1:8083

  • socketTimeout:接收包的超时时间。服务端与客户端传输数据包之间的时间间隔,超过这个间隔将抛出 java.net.SocketTimeoutException: Read timed out

  • connectionRequestTimeout:在使用线程池场景下,从连接池获取到连接的超时时间,时间超出将抛出 org.apache.http.conn.ConnectionPoolTimeoutException: Timeout waiting for connection from pool,线程池默认最大的连接数是 20。

PoolingHttpClientConnectionManager 作为连接池

  • maxTotal:最大连接数

  • defaultMaxPerRoute:每个路由最大连接数

代码样例

  • 依赖配置
<dependency>
	<groupId>org.apache.httpcomponentsgroupId>
	<artifactId>httpclientartifactId>
	<version>4.5.10version>
dependency>
  • 代码样例
    static {
        LayeredConnectionSocketFactory sslsf = null;
        try {
            sslsf = new SSLConnectionSocketFactory(SSLContext.getDefault());
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
            .register("https", sslsf)
            .register("http", new PlainConnectionSocketFactory())
            .build();
        connectionManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
        connectionManager.setMaxTotal(2);
        connectionManager.setDefaultMaxPerRoute(150);
    }

    public static void requestNotExistURL(String url,int connectTimeOut,int connectionRequestTimeout,int socketTimeout){
        try {
            RequestConfig requestConfig = RequestConfig.custom()
                .setConnectTimeout(connectTimeOut)
                .setConnectionRequestTimeout(connectionRequestTimeout)
                .setSocketTimeout(socketTimeout)
                .build();
            CloseableHttpClient httpClient = HttpClients.custom().setConnectionManager(connectionManager)
                .setDefaultRequestConfig(requestConfig).build();

            CloseableHttpResponse response = null;
            HttpGet httpget = new HttpGet(url);
            response = httpClient.execute(httpget);
        }catch (Exception e){
            e.printStackTrace();
        }
    }

UnknownHostException

private static PoolingHttpClientConnectionManager connectionManager = null;

static {
    LayeredConnectionSocketFactory sslsf = null;
    try {
        sslsf = new SSLConnectionSocketFactory(SSLContext.getDefault());
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    }
    Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
        .register("https", sslsf)
        .register("http", new PlainConnectionSocketFactory())
        .build();
    connectionManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
    connectionManager.setMaxTotal(2);
    connectionManager.setDefaultMaxPerRoute(150);
}

public static void requestGoogle(){
    long startTime = System.currentTimeMillis();
    try {
        RequestConfig requestConfig = RequestConfig.custom()
            .setConnectTimeout(1000)
            .setConnectionRequestTimeout(2000)
            .setSocketTimeout(3000)
            .build();
        CloseableHttpClient httpClient = HttpClients.custom().setConnectionManager(connectionManager)
            .setDefaultRequestConfig(requestConfig).build();

        CloseableHttpResponse response = null;
        HttpGet httpget = new HttpGet("http://www.google.com");
        response = httpClient.execute(httpget);
    }catch (Exception e){
        e.printStackTrace();
    }finally {
        System.out.println(System.currentTimeMillis()  - startTime);
    }
}
18:18:51.446 [main] DEBUG org.apache.http.client.protocol.RequestAddCookies - CookieSpec selected: default
18:18:51.461 [main] DEBUG org.apache.http.client.protocol.RequestAuthCache - Auth cache not set in the context
18:18:51.463 [main] DEBUG org.apache.http.impl.conn.PoolingHttpClientConnectionManager - Connection request: [route: {}->http://www.google.com:80][total kept alive: 0; route allocated: 0 of 150; total allocated: 0 of 2]
18:18:51.480 [main] DEBUG org.apache.http.impl.conn.PoolingHttpClientConnectionManager - Connection leased: [id: 0][route: {}->http://www.google.com:80][total kept alive: 0; route allocated: 1 of 150; total allocated: 1 of 2]
18:18:51.484 [main] DEBUG org.apache.http.impl.execchain.MainClientExec - Opening connection {}->http://www.google.com:80
18:19:02.547 [main] DEBUG org.apache.http.impl.conn.DefaultManagedHttpClientConnection - http-outgoing-0: Shutdown connection
18:19:02.547 [main] DEBUG org.apache.http.impl.execchain.MainClientExec - Connection discarded
18:19:02.547 [main] DEBUG org.apache.http.impl.conn.PoolingHttpClientConnectionManager - Connection released: [id: 0][route: {}->http://www.google.com:80][total kept alive: 0; route allocated: 0 of 150; total allocated: 0 of 2]
11208
java.net.UnknownHostException: www.google.com
	at java.net.Inet6AddressImpl.lookupAllHostAddr(Native Method)
	at java.net.InetAddress$2.lookupAllHostAddr(InetAddress.java:929)
	at java.net.InetAddress.getAddressesFromNameService(InetAddress.java:1324)
	at java.net.InetAddress.getAllByName0(InetAddress.java:1277)
	at java.net.InetAddress.getAllByName(InetAddress.java:1193)
	at java.net.InetAddress.getAllByName(InetAddress.java:1127)
	at org.apache.http.impl.conn.SystemDefaultDnsResolver.resolve(SystemDefaultDnsResolver.java:45)
	at org.apache.http.impl.conn.DefaultHttpClientConnectionOperator.connect(DefaultHttpClientConnectionOperator.java:112)
	at org.apache.http.impl.conn.PoolingHttpClientConnectionManager.connect(PoolingHttpClientConnectionManager.java:374)
	at org.apache.http.impl.execchain.MainClientExec.establishRoute(MainClientExec.java:393)
	at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:236)
	at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:186)
	at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:89)
	at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:110)
	at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:185)
	at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:83)
	at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:108)
	at com.company.Main.requestGoogle(Main.java:58)
	at com.company.Main.main(Main.java:91)

当请求被防火墙屏蔽的网站 Google 时,发现方法执行了 10s 才结束,上面 3 个超时时间都失去了作用。

因为请求连接之前,有域名到 IP 的 DNS 解析过程占据了大部分时间。

将域名替换成 IP+端口 之后,访问 Google 才会抛出 ConnectTimeoutException,以及 connectTimeout 参数才会起作用。

C:\Users\LENOVO>nslookup -d www.google.com
------------
Got answer:
    HEADER:
        opcode = QUERY, id = 1, rcode = NOERROR
        header flags:  response, auth. answer, want recursion, recursion avail.
        questions = 1,  answers = 1,  authority records = 0,  additional = 0

    QUESTIONS:
        1.2.168.192.in-addr.arpa, type = PTR, class = IN
    ANSWERS:
    ->  1.2.168.192.in-addr.arpa
        name = R7000-2F35
        ttl = 0 (0 secs)

------------
服务器:  R7000-2F35
Address:  192.168.2.1

DNS request timed out.
    timeout was 2 seconds.
timeout (2 secs)
DNS request timed out.
    timeout was 2 seconds.
timeout (2 secs)
DNS request timed out.
    timeout was 2 seconds.
timeout (2 secs)
DNS request timed out.
    timeout was 2 seconds.
timeout (2 secs)
*** 请求 R7000-2F35 超时

你可能感兴趣的:(Computer,Networks,http)