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

使用Apache HttpClient 4.5.x时遇Address family not supported by protocol错误

问题:Apache HttpClient 4.5 IPv6连接抛出SocketException异常

我开发了一个测试HTTPS连通性的小型应用,使用Apache HttpClient 4.5创建HttpClient并发起HttpGet请求。应用在IPv4环境下运行正常,但连接IPv6时抛出如下异常:

2023-10-05T12:04:38.906Z java.net.SocketException: Address family not supported by protocol
2023-10-05T12:04:38.906Z at java.base/sun.nio.ch.Net.connect0(Native Method)
2023-10-05T12:04:38.906Z at java.base/sun.nio.ch.Net.connect(Net.java:579)
2023-10-05T12:04:38.907Z at java.base/sun.nio.ch.Net.connect(Net.java:568)
2023-10-05T12:04:38.907Z at java.base/sun.nio.ch.NioSocketImpl.connect(NioSocketImpl.java:588)
2023-10-05T12:04:38.907Z at java.base/java.net.SocksSocketImpl.connect(SocksSocketImpl.java:327)
2023-10-05T12:04:38.907Z at java.base/java.net.Socket.connect(Socket.java:633)
2023-10-05T12:04:38.907Z at org.apache.http.conn.ssl.SSLConnectionSocketFactory.connectSocket(SSLConnectionSocketFactory.java:368)
2023-10-05T12:04:38.907Z at org.apache.http.impl.conn.DefaultHttpClientConnectionOperator.connect(DefaultHttpClientConnectionOperator.java:142)
2023-10-05T12:04:38.907Z at org.apache.http.impl.conn.PoolingHttpClientConnectionManager.connect(PoolingHttpClientConnectionManager.java:376)
2023-10-05T12:04:38.907Z at org.apache.http.impl.execchain.MainClientExec.establishRoute(MainClientExec.java:393)
2023-10-05T12:04:38.908Z at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:236)
2023-10-05T12:04:38.908Z at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:186)
2023-10-05T12:04:38.908Z at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:89)
2023-10-05T12:04:38.908Z at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:110)
2023-10-05T12:04:38.908Z at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:185)
2023-10-05T12:04:38.908Z at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:83)
2023-10-05T12:04:38.908Z at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:108)
2023-10-05T12:04:38.908Z at com.ibm.proxy.util.Connection.doTestConnection(Connection.java:123)

TestConnection方法代码

private boolean doTestConnection(String host, ProtocolPojo protocol) {
    boolean connected = false;
    String serverURL = "https://" + host;
    HttpGet getMethodProxyRequest = new HttpGet(serverURL);
    HttpClientBuilder clientBuilder = HttpClients.custom();

    CloseableHttpClient httpClient = clientBuilder
            .setSSLSocketFactory(protocol.getSecureProtocolSocketFactory())
            .build();
    CloseableHttpResponse proxyResponse = null;
    try {
        RequestConfig reqConf = RequestConfig.custom()
                .setLocalAddress(InetAddress.getLocalHost())
                .setAuthenticationEnabled(false).setRedirectsEnabled(false)
                .setConnectTimeout(10000).setSocketTimeout(15000).build();
        getMethodProxyRequest.setConfig(reqConf);
        proxyResponse = httpClient.execute(getMethodProxyRequest);
    } catch (UnknownHostException e) {
        logException(e);
        logMsgInfo(
                "Proxy: not able to resolve localhost: " + e.getMessage());
    } catch (IOException e) {
        logException(e);
    } finally {
        if (proxyResponse != null
                && proxyResponse.getStatusLine() != null) {
            logMsgInfo(
                    "Proxy: " + proxyResponse.getStatusLine().toString());
            logMsgInfo("Proxy: "
                    + proxyResponse.getStatusLine().getStatusCode());
            connected = (proxyResponse.getStatusLine()
                    .getStatusCode() == 200);
        }
        try {
            httpClient.close();
        } catch (IOException e) {
            logException(e);
        }
    }
    return connected;
}

ProtocolPojo类代码

public class ProtocolPojo {

    private String schema;
    private int port;
    private StrictSSLProtocolSocketFactory secureProtocolSocketFactory;

    public ASMProtocol(String schema,
            StrictSSLProtocolSocketFactory secureProtocolSocketFactory,
            int port) {
        this.schema = schema;
        this.port = port;
        this.secureProtocolSocketFactory = secureProtocolSocketFactory;
    }

    public String getSchema() {
        return schema;
    }

    public int getPort() {
        return port;
    }
    
    /**
     * org.apache.http.conn.ssl.SSLConnectionSocketFactory - that 
     * can be used to verify the host certificate that is 
     * recived.
     */
    public SSLConnectionSocketFactory getSecureProtocolSocketFactory() {
        return secureProtocolSocketFactory.getSSLConnectionSocketFactory();
    }

}

已通过浏览器手动测试IPv6,确认可正常访问。怀疑问题出在Apache HttpClient 4.5中,请问是否有处理该异常的方法?这是否是环境问题?


解决方案

核心问题定位

代码中RequestConfig.custom().setLocalAddress(InetAddress.getLocalHost())强制绑定了本地IPv4地址。当目标是IPv6地址时,用IPv4本地地址去连接IPv6服务,会触发Address family not supported by protocol异常——因为IPv4和IPv6属于不同的地址族,无法跨族建立连接。

修复方法

  1. 最简修复:直接移除setLocalAddress(InetAddress.getLocalHost())配置,让HttpClient自动匹配目标地址类型选择对应的本地地址族:
RequestConfig reqConf = RequestConfig.custom()
        .setAuthenticationEnabled(false)
        .setRedirectsEnabled(false)
        .setConnectTimeout(10000)
        .setSocketTimeout(15000)
        .build();
  1. 动态绑定本地地址(如果必须绑定):如果业务需要绑定特定本地地址,需根据目标主机的地址类型动态选择IPv4或IPv6本地地址:
InetAddress localAddress = null;
// 解析目标主机地址,判断地址类型
InetAddress[] targetAddrs = InetAddress.getAllByName(host);
for (InetAddress addr : targetAddrs) {
    if (addr instanceof Inet6Address) {
        // 查找可用的本地IPv6地址(非回环)
        Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
        while (interfaces.hasMoreElements()) {
            NetworkInterface ni = interfaces.nextElement();
            Enumeration<InetAddress> inetAddrs = ni.getInetAddresses();
            while (inetAddrs.hasMoreElements()) {
                InetAddress localAddr = inetAddrs.nextElement();
                if (localAddr instanceof Inet6Address && !localAddr.isLoopbackAddress()) {
                    localAddress = localAddr;
                    break;
                }
            }
            if (localAddress != null) break;
        }
        break;
    } else {
        // 目标是IPv4,绑定本地IPv4地址
        localAddress = InetAddress.getLocalHost();
        break;
    }
}

RequestConfig reqConf = RequestConfig.custom()
        .setLocalAddress(localAddress)
        .setAuthenticationEnabled(false)
        .setRedirectsEnabled(false)
        .setConnectTimeout(10000)
        .setSocketTimeout(15000)
        .build();

环境排查补充

若修复代码后仍异常,检查以下内容:

  • JVM参数:确认未设置java.net.preferIPv4Stack=true,该参数会强制JVM优先使用IPv4,禁用IPv6支持。
  • 系统网络配置:验证主机已正确配置IPv6地址,且网络可路由,防火墙未拦截IPv6流量。
  • HttpClient版本:确保使用的是Apache HttpClient 4.5的稳定版本,避免依赖包冲突导致的IPv6支持异常。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 01:40:54