使用SSL时,Apache HttpClient会抛出SocketTimeoutException

时间:2017-09-20 17:35:54

标签: java apache-httpclient-4.x

我使用的是Apache httpclient 4.3.6和httpcore 4.3.3(与opensaml 3.3.0捆绑在一起)。我尝试通过HTTPS通过代理获取网页,但每次都会获得SocketTimeoutException。 HTTP连接工作正常。特定的超时并不重要;只需要更长的时间就能用更高的值来失败。

示例代码:

public class TestGet {
    private static final int TIMEOUT = 7000;

    public static void main(String[] args) throws Exception {
        URL url   = new URL("https://www.google.com");
        URL proxy = new URL("https://myproxy:9090/");
        try {
            String s = get(url, proxy);
            System.out.println(s);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private static String get(URL url, URL proxy) throws IOException, URISyntaxException {
        CloseableHttpClient client  = HttpClients.createDefault();
        HttpGet             request = new HttpGet(url.toURI());
        HttpHost            host    = null;

        if (proxy != null) {
            host = new HttpHost(proxy.getHost(), proxy.getPort(), proxy.getProtocol());
        }

        RequestConfig config = RequestConfig.custom()
            .setProxy(host)
            .setConnectionRequestTimeout(TIMEOUT)
            .setConnectTimeout(TIMEOUT)
            .setSocketTimeout(TIMEOUT)
            .build();
        request.setConfig(config);

        try {
            CloseableHttpResponse response = client.execute(request);
            try {
                System.out.println(response.getStatusLine());
                return EntityUtils.toString(response.getEntity());
            } finally {
                response.close();
            }
        } finally {
            client.close();
        }
    }
}

尝试连接代理时抛出异常。堆栈跟踪是

org.apache.http.conn.ConnectTimeoutException: Connect to <proxy> failed: Read 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:371)
    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 authentication.TestGet.get(TestGet.java:47)
    at authentication.TestGet.main(TestGet.java:22)
Caused by: java.net.SocketTimeoutException: Read timed out
    at java.net.SocketInputStream.socketRead0(Native Method)
    at java.net.SocketInputStream.socketRead(Unknown Source)
    at java.net.SocketInputStream.read(Unknown Source)
    at java.net.SocketInputStream.read(Unknown Source)
    at sun.security.ssl.InputRecord.readFully(Unknown Source)
    at sun.security.ssl.InputRecord.read(Unknown Source)
    at sun.security.ssl.SSLSocketImpl.readRecord(Unknown Source)
    at sun.security.ssl.SSLSocketImpl.performInitialHandshake(Unknown Source)
    at sun.security.ssl.SSLSocketImpl.startHandshake(Unknown Source)
    at sun.security.ssl.SSLSocketImpl.startHandshake(Unknown Source)
    at org.apache.http.conn.ssl.SSLConnectionSocketFactory.createLayeredSocket(SSLConnectionSocketFactory.java:290)
    at org.apache.http.conn.ssl.SSLConnectionSocketFactory.connectSocket(SSLConnectionSocketFactory.java:259)
    at org.apache.http.impl.conn.HttpClientConnectionOperator.connect(HttpClientConnectionOperator.java:125)
    ... 11 more

这看起来很像Apache问题HTTPCLIENT-1478,它与未设置的套接字超时有关。该错误在4.3.4(我使用4.3.6)中得到了修正,虽然有些评论表明在以后的版本中仍然需要解决方法,但它们并不适用于我。更重要的是,我已经进入SSLConnectionSocketFactory.createConnection()并确认套接字超时被设置为非零值。

我被困住了。我不知道连接失败的原因,并且无法比SSLSocketImpl.startHandshake()调用更深入地进行故障排除。可能有什么问题,我该如何解决?

2 个答案:

答案 0 :(得分:2)

请勿使用.setConnectionRequestTimeout(TIMEOUT)

或者,等待很长时间,看看会发生什么。

阅读this了解详情。

答案 1 :(得分:0)

[问题作者回答;可能对其他人的适用性有限]

确认代理服务器支持HTTPS。即使在与目标服务器的连接上使用HTTPS,它也可能期望纯HTTP。如果代理不支持HTTPS,它将不响应客户端问候消息;从而导致套接字超时。

javax.net.debug系统属性设置为ssl将启用SSL协商的调试日志记录。如果您看到没有后续ServerHello的ClientHello,则代理服务器可能不支持HTTPS。将代理从https://更改为http://,然后重试。