【问题标题】:Apache HttpClient 4.3 does not honor keep aliveApache HttpClient 4.3 不尊重保持活动状态
【发布时间】:2014-01-23 03:30:50
【问题描述】:

在 nGinx 服务器端,为客户端设置的连接保持活动状态最长为 30 秒。但是使用此代码和附加的日志,HttpClient 4.3。不尊重保持活动并在每次请求后关闭连接。为什么会这样?

在反复尝试 netstat -an 并发现客户端在 for 循环执行期间的不同时间打开不同的端口并且 FIN 状态每 2 秒变化一次后,我得出了这个结论。

下面给出的日志还显示每次请求后连接都关闭

static ConnectionKeepAliveStrategy myStrategy = new ConnectionKeepAliveStrategy() {
    public long getKeepAliveDuration(HttpResponse response, HttpContext context) {
            return 30 * 1000;
    }
};

public static void main(String[] args) throws Exception {

    java.util.logging.Logger.getLogger("org.apache.http.wire").setLevel(java.util.logging.Level.FINER);
    java.util.logging.Logger.getLogger("org.apache.http.headers").setLevel(java.util.logging.Level.FINER);

    System.setProperty("org.apache.commons.logging.Log", "org.apache.commons.logging.impl.SimpleLog");
    System.setProperty("org.apache.commons.logging.simplelog.showdatetime", "true");
    System.setProperty("org.apache.commons.logging.simplelog.log.httpclient.wire", "debug");
    System.setProperty("org.apache.commons.logging.simplelog.log.org.apache.http", "debug");
    System.setProperty("org.apache.commons.logging.simplelog.log.org.apache.http.headers", "debug");

    callServer();
}

public static void callServer() throws Exception {

    KeyStore keyStore = KeyStore.getInstance("pkcs12");

    FileInputStream instream = new FileInputStream(new File("/engineering/workspace/nginx_pilot/keystores/clientkeystore.pkcs"));
    try {
        keyStore.load(instream, "****".toCharArray());
    } finally {
        instream.close();
    }

    KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());

    instream = new FileInputStream(new File("/engineering/workspace/nginx_pilot/keystores/serverKeystore.jks"));
    try {
        trustStore.load(instream, "****".toCharArray());
    } finally {
        instream.close();
    }

    SSLContext sslContext = SSLContexts.custom().loadKeyMaterial(keyStore, "pass".toCharArray()).loadTrustMaterial(trustStore).build();
    SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext, SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);

    CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).setConnectionReuseStrategy(DefaultConnectionReuseStrategy.INSTANCE).build();

    CloseableHttpResponse response = null;

    try {
        HttpGet httpget = new HttpGet("https://" + getString() + ":8443/GenevaServers/GetConfig/unit.test.asset.ast1");

        System.out.println("executing request" + httpget.getRequestLine());

        for (int i = 0; i < 10000; i++) {
            System.out.println("Beginning");
            long currentTimeMillis = System.currentTimeMillis();
            response = httpclient.execute(httpget);
            System.out.println((System.currentTimeMillis() - currentTimeMillis) + "ms");
            HttpEntity entity = response.getEntity();
            System.out.println(IOUtils.toString(entity.getContent()));
            EntityUtils.consume(entity);
            System.out.println("End");
        }
    } catch (Exception e) {
        e.printStackTrace();
    }finally {
        response.close();
        httpclient.close();
    }
}

这些是日志。

2014/01/22 19:24:50:252 PST [DEBUG] RequestAddCookies - CookieSpec selected: best-match
2014/01/22 19:24:50:252 PST [DEBUG] RequestAuthCache - Auth cache not set in the context
2014/01/22 19:24:50:252 PST [DEBUG] PoolingHttpClientConnectionManager - Connection      request: [route: {s}->https://ichor.corp.com:8443][total kept alive: 2; route allocated: 2 of 2; total allocated: 2 of 20]
2014/01/22 19:24:50:253 PST [DEBUG] DefaultManagedHttpClientConnection - http-outgoing-0:    Close connection
2014/01/22 19:24:50:254 PST [DEBUG] PoolingHttpClientConnectionManager - Connection leased: [id: 2][route: {s}->https://ichor.corp.com:8443][total kept alive: 1; route allocated:    2 of 2; total allocated: 2 of 20]
2014/01/22 19:24:50:254 PST [DEBUG] MainClientExec - Opening connection {s}-  >https://ichor.corp.com:8443
2014/01/22 19:24:50:254 PST [DEBUG] HttpClientConnectionManager - Connecting to    ichor.corp.com/17.169.1.18:8443
2014/01/22 19:24:50:392 PST [DEBUG] MainClientExec - Executing request GET /GenevaServers/GetConfig/unit.test.asset.ast1 HTTP/1.1
2014/01/22 19:24:50:392 PST [DEBUG] MainClientExec - Target auth state: UNCHALLENGED
2014/01/22 19:24:50:392 PST [DEBUG] MainClientExec - Proxy auth state: UNCHALLENGED
2014/01/22 19:24:50:392 PST [DEBUG] headers - http-outgoing-2 >> GET   /GenevaServers/GetConfig/unit.test.asset.ast1 HTTP/1.1
2014/01/22 19:24:50:392 PST [DEBUG] headers - http-outgoing-2 >> Host: ichor.corp.com:8443
2014/01/22 19:24:50:392 PST [DEBUG] headers - http-outgoing-2 >> Connection: Keep-Alive
2014/01/22 19:24:50:392 PST [DEBUG] headers - http-outgoing-2 >> User-Agent: Apache- HttpClient/4.3.1 (java 1.5)
2014/01/22 19:24:50:392 PST [DEBUG] headers - http-outgoing-2 >> Accept-Encoding: gzip,deflate
2014/01/22 19:24:50:392 PST [DEBUG] wire - http-outgoing-2 >> "GET /GenevaServers/GetConfig/unit.test.asset.ast1 HTTP/1.1[\r][\n]"
2014/01/22 19:24:50:392 PST [DEBUG] wire - http-outgoing-2 >> "Host: ichor.corp.com:8443[\r][\n]"
2014/01/22 19:24:50:392 PST [DEBUG] wire - http-outgoing-2 >> "Connection: Keep-Alive[\r][\n]"
2014/01/22 19:24:50:392 PST [DEBUG] wire - http-outgoing-2 >> "User-Agent: Apache-HttpClient/4.3.1 (java 1.5)[\r][\n]"
2014/01/22 19:24:50:392 PST [DEBUG] wire - http-outgoing-2 >> "Accept-Encoding: gzip,deflate[\r][\n]"
2014/01/22 19:24:50:393 PST [DEBUG] wire - http-outgoing-2 >> "[\r][\n]"
2014/01/22 19:24:50:462 PST [DEBUG] wire - http-outgoing-2 << "HTTP/1.1 200 OK[\r][\n]"
2014/01/22 19:24:50:462 PST [DEBUG] wire - http-outgoing-2 << "Server: nginx/1.4.1[\r][\n]"
2014/01/22 19:24:50:463 PST [DEBUG] wire - http-outgoing-2 << "Date: Thu, 23 Jan 2014 03:24:09 GMT[\r][\n]"
2014/01/22 19:24:50:463 PST [DEBUG] wire - http-outgoing-2 << "Content-Type: application/json[\r][\n]"
2014/01/22 19:24:50:463 PST [DEBUG] wire - http-outgoing-2 << "Content-Length: 270[\r][\n]"
2014/01/22 19:24:50:463 PST [DEBUG] wire - http-outgoing-2 << "Connection: keep-alive[\r][\n]"
2014/01/22 19:24:50:463 PST [DEBUG] wire - http-outgoing-2 << "[\r][\n]"

任何建议都会有很大帮助。提前谢谢你。

【问题讨论】:

    标签: apache-httpclient-4.x keep-alive


    【解决方案1】:

    当然可以,但这是特例

    SSLContext sslContext = SSLContexts.custom().loadKeyMaterial(keyStore, "pass".toCharArray()).loadTrustMaterial(trustStore).build();
    SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext, SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
    

    您正在使用 SSL 密钥向目标服务器进行身份验证。这使得连接代表一个特定的用户并携带一个特定的安全上下文。换句话说,连接具有特定的状态(用户主体)。您很可能不希望将此连接租给可能代表完全不同用户的任意执行线程,对吗? HttpClient 4(与其前身不同)跟踪有状态连接并确保它们不能被具有不同执行上下文的线程重用。

    有几种方法可以解决问题

    1. 推荐。让所有逻辑相关的请求共享same execution context

    2. 手动manage connection state

    3. 禁用连接状态跟踪。该措施会产生安全影响,因此必须慎重考虑

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-03-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多