You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java 8+HttpClient 4.3.5通过代理无法连接HTTPS的问题

问题:Apache HttpClient 4.3.5通过代理访问HTTPS失败,HTTP正常

我使用Apache HttpClient 4.3.5编写Java代码通过代理访问网络,HTTP地址可正常返回IP,但HTTPS地址抛出javax.net.ssl.SSLException: Received fatal alert: internal_error异常。已配置忽略所有证书验证,该问题在Java 8 build 181和Java 19环境中均会出现。

代码实现

import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.BasicResponseHandler;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.ssl.SSLContextBuilder;
import org.junit.Test;

import java.net.Authenticator;
import java.net.URI;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;

public class ConnectToHttpsSafelyTest {

    @Test
    public void httpAndHttpsWithProxyTest() throws Exception {
        System.out.println(executeHttpCall("http://myexternalip.com/raw"));
        System.out.println(executeHttpCall("https://myexternalip.com/raw"));
    }


    private Object executeHttpCall(final String url) throws Exception{
        final SSLContextBuilder sslBuilder = new SSLContextBuilder();
        sslBuilder.loadTrustMaterial(null,(chain,authType)->true);
        final HttpClientBuilder httpClient = HttpClientBuilder.create();
        setUpProxy(httpClient,sslBuilder);
        final HttpRequestBase request = new HttpGet();
        ((HttpGet) request).setURI(URI.create(url));
        final Object obj = httpClient.build().execute(request, new BasicResponseHandler(), HttpClientContext.create());
        return obj;
    }


    private void setUpProxy(HttpClientBuilder builder, SSLContextBuilder sslBuilder)
            throws NoSuchAlgorithmException, KeyManagementException {
        final SSLConnectionSocketFactory sslConnectionSocketFactory =
                new SSLConnectionSocketFactory(sslBuilder.build(), new String[]{"SSLv2Hello", "SSLv3", "TLSv1", "TLSv1.1", "TLSv1.2"}, null, NoopHostnameVerifier.INSTANCE);

        Authenticator.setDefault(null);
        HttpHost httpProxy = new HttpHost("proxyHost", proxyPort, "http");
        CredentialsProvider cred_provider = new BasicCredentialsProvider();
        cred_provider.setCredentials(new AuthScope(httpProxy), new UsernamePasswordCredentials("proxyUser", "proxyPassword"));

        final PoolingHttpClientConnectionManager conn_mgr
                = new PoolingHttpClientConnectionManager(RegistryBuilder.
                <ConnectionSocketFactory>create()
                .register("http", PlainConnectionSocketFactory.getSocketFactory())
                .register("https", sslConnectionSocketFactory)
                .build());
        conn_mgr.setDefaultMaxPerRoute(Integer.MAX_VALUE);
        conn_mgr.setMaxTotal(Integer.MAX_VALUE);
        builder.setConnectionManager(conn_mgr)
                .setProxy(httpProxy)
                .setDefaultCredentialsProvider(cred_provider);
        builder.setSSLSocketFactory(sslConnectionSocketFactory);
    }
}

异常信息

220.1.72.193

javax.net.ssl.SSLException: Received fatal alert: internal_error

    at sun.security.ssl.Alerts.getSSLException(Alerts.java:208)
    at sun.security.ssl.Alerts.getSSLException(Alerts.java:154)
    at sun.security.ssl.SSLSocketImpl.recvAlert(SSLSocketImpl.java:2038)
    at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1135)
    at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1385)
    at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1413)
    at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1397)
    at org.apache.http.conn.ssl.SSLConnectionSocketFactory.createLayeredSocket(SSLConnectionSocketFactory.java:396)
    at org.apache.http.impl.conn.DefaultHttpClientConnectionOperator.upgrade(DefaultHttpClientConnectionOperator.java:193)
    at org.apache.http.impl.conn.PoolingHttpClientConnectionManager.upgrade(PoolingHttpClientConnectionManager.java:389)
    at org.apache.http.impl.execchain.MainClientExec.establishRoute(MainClientExec.java:416)
    at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:237)
    at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:185)
    at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:89)
    at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:111)
    at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:185)
    at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:72)
    at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:221)
    at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:165)

解决方案

1. 移除重复的SSL连接工厂配置

代码中同时给连接管理器注册了SSL连接工厂,又调用builder.setSSLSocketFactory(),这会导致HttpClient内部配置冲突。直接删除这行代码:

builder.setSSLSocketFactory(sslConnectionSocketFactory);

2. 调整TLS协议版本

禁用过时的SSLv2Hello、SSLv3协议,这些协议可能被代理或目标服务器拒绝,只保留现代TLS版本:

final SSLConnectionSocketFactory sslConnectionSocketFactory =
        new SSLConnectionSocketFactory(sslBuilder.build(), 
                new String[]{"TLSv1.2", "TLSv1.3"}, // 优先使用TLSv1.3,不支持则降级到TLSv1.2
                null, 
                NoopHostnameVerifier.INSTANCE);

3. 修正连接池配置

不要将连接池最大连接数设置为Integer.MAX_VALUE,这会导致系统资源耗尽,改为合理的值:

conn_mgr.setDefaultMaxPerRoute(20); // 每个路由的最大连接数
conn_mgr.setMaxTotal(100); // 连接池总最大连接数

4. 确认代理支持CONNECT隧道

HTTPS通过代理访问需要代理服务器支持CONNECT方法,请联系运维确认代理是否允许CONNECT请求,以及是否开放了443端口的隧道权限。

5. 启用SSL调试排查

添加JVM启动参数启用SSL握手调试,查看详细错误信息:

-Djavax.net.debug=ssl:handshake:verbose

根据日志可以定位是协议不匹配、代理认证失败还是目标服务器证书问题。

优化后的核心代码

private void setUpProxy(HttpClientBuilder builder, SSLContextBuilder sslBuilder)
        throws NoSuchAlgorithmException, KeyManagementException {
    final SSLConnectionSocketFactory sslConnectionSocketFactory =
            new SSLConnectionSocketFactory(sslBuilder.build(), 
                    new String[]{"TLSv1.2", "TLSv1.3"}, 
                    null, 
                    NoopHostnameVerifier.INSTANCE);

    Authenticator.setDefault(null);
    HttpHost httpProxy = new HttpHost("proxyHost", proxyPort, "http");
    CredentialsProvider cred_provider = new BasicCredentialsProvider();
    cred_provider.setCredentials(new AuthScope(httpProxy), 
            new UsernamePasswordCredentials("proxyUser", "proxyPassword"));

    final PoolingHttpClientConnectionManager conn_mgr
            = new PoolingHttpClientConnectionManager(RegistryBuilder.
            <ConnectionSocketFactory>create()
            .register("http", PlainConnectionSocketFactory.getSocketFactory())
            .register("https", sslConnectionSocketFactory)
            .build());
    conn_mgr.setDefaultMaxPerRoute(20);
    conn_mgr.setMaxTotal(100);
    builder.setConnectionManager(conn_mgr)
            .setProxy(httpProxy)
            .setDefaultCredentialsProvider(cred_provider);
    // 已移除builder.setSSLSocketFactory调用
}

内容的提问来源于stack exchange,提问作者chiperortiz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 09:45:04