【问题标题】:apache httpclient 4.5.1 making only SSL connections to non-ssl sites, and failingapache httpclient 4.5.1 仅与非 SSL 站点建立 SSL 连接,但失败
【发布时间】:2016-04-10 06:15:42
【问题描述】:

目前我在 jdk/tomcat v6 上使用 httpclient 4.2.5,它运行良好。为了升级,我在 jdk/tomcat v8 上移动到 httpclient 4.5.1,现在得到不同的错误如下:

javax.net.ssl.SSLHandshakeException: Remote host closed connection during handshake
    at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:992)
    at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1375)
    at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1403)
    at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1387)
    at org.apache.http.conn.ssl.SSLConnectionSocketFactory.createLayeredSocket(SSLConnectionSocketFactory.java:394)
    at org.apache.http.conn.ssl.SSLConnectionSocketFactory.connectSocket(SSLConnectionSocketFactory.java:353)
    at org.apache.http.impl.conn.DefaultHttpClientConnectionOperator.connect(DefaultHttpClientConnectionOperator.java:134)
    at org.apache.http.impl.conn.PoolingHttpClientConnectionManager.connect(PoolingHttpClientConnectionManager.java:353)
    at org.apache.http.impl.execchain.MainClientExec.establishRoute(MainClientExec.java:388)
    at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:236)
    at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:184)
    at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:88)
    at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:110)
    at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:184)
    at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:82)
    at com.temp.MyHttpClient.makeHttpRequest(MyHttpClient.java:275)
    .......
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:745)
Caused by: java.io.EOFException: SSL peer shut down incorrectly
    at sun.security.ssl.InputRecord.read(InputRecord.java:505)
    at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:973)
    ... 25 more

java.lang.Exception: Unrecognized SSL message, plaintext connection?
    ....
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:745)
Caused by: javax.net.ssl.SSLException: Unrecognized SSL message, plaintext connection?
    at sun.security.ssl.InputRecord.handleUnknownRecord(InputRecord.java:710)
    at sun.security.ssl.InputRecord.read(InputRecord.java:527)
    at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:973)
    at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1375)
    at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1403)
    at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1387)
    at org.apache.http.conn.ssl.SSLConnectionSocketFactory.createLayeredSocket(SSLConnectionSocketFactory.java:394)
    at org.apache.http.conn.ssl.SSLConnectionSocketFactory.connectSocket(SSLConnectionSocketFactory.java:353)
    at org.apache.http.impl.conn.DefaultHttpClientConnectionOperator.connect(DefaultHttpClientConnectionOperator.java:134)
    at org.apache.http.impl.conn.PoolingHttpClientConnectionManager.connect(PoolingHttpClientConnectionManager.java:353)
    at org.apache.http.impl.execchain.MainClientExec.establishRoute(MainClientExec.java:388)
    at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:236)
    at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:184)
    at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:88)
    at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:110)
    at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:184)
    at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:82)

java.lang.Exception: Searching source item B00OFLNE1C threw an error: Connection reset
    .....
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:745)
Caused by: java.net.SocketException: Connection reset
    at java.net.SocketInputStream.read(SocketInputStream.java:209)
    at java.net.SocketInputStream.read(SocketInputStream.java:141)
    at sun.security.ssl.InputRecord.readFully(InputRecord.java:465)
    at sun.security.ssl.InputRecord.read(InputRecord.java:503)
    at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:973)
    at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1375)
    at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1403)
    at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1387)
    at org.apache.http.conn.ssl.SSLConnectionSocketFactory.createLayeredSocket(SSLConnectionSocketFactory.java:394)
    at org.apache.http.conn.ssl.SSLConnectionSocketFactory.connectSocket(SSLConnectionSocketFactory.java:353)
    at org.apache.http.impl.conn.DefaultHttpClientConnectionOperator.connect(DefaultHttpClientConnectionOperator.java:134)
    at org.apache.http.impl.conn.PoolingHttpClientConnectionManager.connect(PoolingHttpClientConnectionManager.java:353)
    at org.apache.http.impl.execchain.MainClientExec.establishRoute(MainClientExec.java:388)
    at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:236)
    at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:184)
    at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:88)
    at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:110)
    at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:184)
    at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:82)
    ......

java.lang.Exception: Connect to 189.219.54.22:10000 [/189.219.54.22] failed: Connection timed out: connect
    ...
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:745)
Caused by: org.apache.http.conn.HttpHostConnectException: Connect to 189.219.54.22:10000 [/189.219.54.22] failed: Connection timed out: connect
    at org.apache.http.impl.conn.DefaultHttpClientConnectionOperator.connect(DefaultHttpClientConnectionOperator.java:151)
    at org.apache.http.impl.conn.PoolingHttpClientConnectionManager.connect(PoolingHttpClientConnectionManager.java:353)
    at org.apache.http.impl.execchain.MainClientExec.establishRoute(MainClientExec.java:388)
    at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:236)
    at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:184)
    at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:88)
    at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:110)
    at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:184)
    at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:82)
    ......
    ... 4 more
Caused by: java.net.ConnectException: Connection timed out: connect
    at java.net.DualStackPlainSocketImpl.waitForConnect(Native Method)
    at java.net.DualStackPlainSocketImpl.socketConnect(DualStackPlainSocketImpl.java:85)
    at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:350)
    at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:206)
    at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:188)
    at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:172)
    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:74)
    at org.apache.http.impl.conn.DefaultHttpClientConnectionOperator.connect(DefaultHttpClientConnectionOperator.java:134)
    ... 19 more

我搜索并发现第一个错误(SSL 对等体关闭不正确)表明与 2 个 jdks 中的协议差异有关,但按照建议使用“-Dhttps.protocols=TLSv1,SSLv3”并没有帮助. 但我认为其余的错误是由于 httpclient 试图与一个所谓的 http 站点建立 ssl 连接(我给它的 url 也只有 http - 任何地方都没有'https')。

然后我尝试使用自定义的socketConnectionRegistry,如

ConnectionSocketFactory plainsf = PlainConnectionSocketFactory.getSocketFactory();
        LayeredConnectionSocketFactory sslsf = SSLConnectionSocketFactory.getSocketFactory();
        Registry<ConnectionSocketFactory> sockConnRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
            .register("http", plainsf)
            .register("https", sslsf)
        .build();

并使用它来构建池连接管理器并使用它来构建自定义客户端,但错误仍然存​​在。

有趣的是,它的旧版本 4.2.5 在 jdk/tomcat v6 上运行良好,并且可以毫无错误地连接到这些站点。不知道我哪里做错了。


更新:1 月 12 日

@Oleg 我还没有尝试过你上面给出的替代协议,但仍在尝试让新的 httpclient 4.5.1 连接到 http 本身上的代理站点,这总是超时。 我创建了两个单独的 Eclipse 项目,一个使用 HC 4.2.5(在 jdk-6 上),另一个使用 HC 4.5.1(在 jdk-8 上),发现旧的 HC 可以轻松连接到代理和目标并获取目标html,但较新的 HC 在代理连接上超时.. 我还发现如果我在构建客户端时在 HC 4.5 上设置了代理(即

CloseableHttpClient httpClient = HttpClients.custom()
    .setRoutePlanner(routePlanner)
    ......
    .setProxy(proxy)
    .build();

然后它完美连接,并带来了html, 但是当我使用自定义RoutePlanner并通过它设置代理时,就会出现上述问题(超时)。这是自定义路线规划器:

static class ProxyRoutePlanner implements HttpRoutePlanner {
    public HttpHost proxy = null;
    @Override
    public HttpRoute determineRoute(HttpHost target,
            HttpRequest request, HttpContext context)
            throws HttpException {
        if (null == proxy)
            return new HttpRoute(target);
        return new HttpRoute(target, null, proxy, "https".equalsIgnoreCase(target.getSchemeName()));
    }
}

并且我在发出请求之前设置了代理主机(每个请求之前的不同代理,通过一组代理循环循环)。在这种情况下它会失败。

你能看出什么是错误的吗?


更多更新:

其实,如果我设置了

.setRoutePlanner(routePlanner)

在构建自定义 HC 时,它会忽略通过 .setProxy(...) 或通过 RequestConfig 设置的任何代理,因为 routePlanner 中没有设置代理(似乎有意义)。因此它直接连接到目标并获取页面。 但是如果我在 routePlanner 中设置代理,或者在 HC 构建中删除规划器并通过 reqConfig 或 .setProxy 设置代理,它会尝试连接到代理,然后再次失败(超时)。

我在 HC 4.2 中设置代理如下:

HttpHost proxy = new HttpHost(proxyHost, proxyPort, proxyProtocol);
    httpClient.getParams().setParameter(ConnRoutePNames.DEFAULT_PROXY, proxy);

我现在完全迷路了。在 HC 4.2 中设置代理是否正确?如何验证 HC 4.2 是否使用如上设置的代理,或者如何在 4.5 中正确设置代理?

【问题讨论】:

    标签: java ssl tomcat apache-httpclient-4.x apache-httpcomponents


    【解决方案1】:

    除非明确指示这样做,否则 HttpClient 不会使用“https.protocols”属性(或任何其他属性)

    CloseableHttpClient client = HttpClients.createSystem();
    

    从 4.5 版开始,HttpClient 默认禁用 SSLv3 协议版本

    但是,可以使用自定义 SSL 连接工厂明确设置支持的 SSL 协议版本

    SSLContext sslcontext = SSLContexts.createSystemDefault();
    SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(
            sslcontext, new String[] { "TLSv1", "SSLv3" }, null,
            SSLConnectionSocketFactory.getDefaultHostnameVerifier());
    
    Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
            .register("http", PlainConnectionSocketFactory.INSTANCE)
            .register("https", sslConnectionSocketFactory)
            .build();
    PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
    CloseableHttpClient httpClient = HttpClients.custom()
            .setConnectionManager(cm)
            .build();
    

    【讨论】:

    • 谢谢。我会尝试你的 cmets 来解决协议问题,但是你怀疑客户端总是建立 ssl 连接,即使是 http url?
    • 我没有看到支持这个假设的证据
    • 前 3 个错误的堆栈跟踪显示使用了 ssl 套接字/连接。使用 sslSocketConnectionFactory 等不是这个指标吗?虽然第四个(连接超时错误)确实显示了使用普通套接字。
    • 不,它没有。有证据表明 HttpClient 尝试使用 SSL 连接工厂连接到 http 端点。更不用说请求可以从 http:// 重定向到 https://
    猜你喜欢
    • 2011-01-18
    • 1970-01-01
    • 1970-01-01
    • 2020-12-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-22
    • 1970-01-01
    相关资源
    最近更新 更多