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

如何在Java代码中解析服务FQDN至IP地址(无/etc/hosts权限)

解决方案

你的核心矛盾是:既需要让Java将abc.xyz.com解析到指定IP,又要保证SSL握手时使用正确的FQDN(避免证书验证失败)。以下是几种可行的代码层面解决方案:

方法1:针对HttpsURLConnection的局部处理(最稳妥,无全局影响)

直接连接到目标IP,但强制SSL验证时使用原FQDN,同时设置请求头的Host字段匹配服务端预期:

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;

public class HttpsConnectionFix {
    public static void main(String[] args) throws IOException {
        String targetFqdn = "abc.xyz.com";
        String targetIp = "100.70.125.57";

        // 构造指向IP的HTTPS URL
        URL url = new URL("https://" + targetIp);
        HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();

        // 覆盖主机名验证逻辑,验证原FQDN而非IP
        conn.setHostnameVerifier((hostname, session) -> {
            // 优先验证原FQDN,也可复用默认验证逻辑
            return targetFqdn.equals(hostname) || HostnameVerifier.getDefault().verify(targetFqdn, session);
        });

        // 设置请求头Host字段,确保服务端识别请求目标
        conn.setRequestProperty("Host", targetFqdn);

        // 后续正常处理连接流
        try (InputStream in = conn.getInputStream()) {
            // 读取响应内容
        }
    }
}

方法2:手动构建SSL Socket连接

如果需要更底层的控制,可以直接创建Socket连接到IP,再包装为SSL Socket并指定验证的主机名:

import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;

public class SslSocketFix {
    public static void main(String[] args) throws IOException {
        String targetFqdn = "abc.xyz.com";
        String targetIp = "100.70.125.57";
        int port = 443;

        // 建立到目标IP的基础Socket
        try (Socket plainSocket = new Socket(targetIp, port)) {
            // 创建SSL Socket,指定握手时验证的主机名为原FQDN
            SSLSocketFactory sslFactory = (SSLSocketFactory) SSLSocketFactory.getDefault();
            try (SSLSocket sslSocket = (SSLSocket) sslFactory.createSocket(
                    plainSocket,
                    targetFqdn,
                    port,
                    true // 自动关闭底层Socket
            )) {
                // 启动SSL握手
                sslSocket.startHandshake();
                
                // 后续通过sslSocket进行读写操作
                try (OutputStream out = sslSocket.getOutputStream();
                     InputStream in = sslSocket.getInputStream()) {
                    // 发送请求、读取响应
                }
            }
        }
    }
}

方法3:使用OkHttp客户端的自定义DNS解析(适合用OkHttp的场景)

如果项目使用OkHttp作为HTTP客户端,可以直接自定义DNS规则,既实现FQDN到IP的映射,又自动处理SSL主机名验证:

import okhttp3.Dns;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;

import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Collections;

public class OkHttpDnsFix {
    public static void main(String[] args) throws Exception {
        String targetFqdn = "abc.xyz.com";
        String targetIp = "100.70.125.57";

        OkHttpClient client = new OkHttpClient.Builder()
                .dns(hostname -> {
                    if (targetFqdn.equals(hostname)) {
                        // 强制解析到指定IP
                        return Collections.singletonList(InetAddress.getByAddress(hostname, new byte[]{100, 70, 125, 57}));
                    }
                    // 其他域名使用系统默认DNS解析
                    return Dns.SYSTEM.lookup(hostname);
                })
                .build();

        // 正常请求原FQDN即可,OkHttp会用自定义DNS解析到目标IP
        Request request = new Request.Builder()
                .url("https://" + targetFqdn)
                .build();

        try (Response response = client.newCall(request).execute()) {
            // 处理响应
        }
    }
}

方法4:全局DNS解析替换(Java 9+,影响整个JVM)

如果需要所有JVM内的连接都将abc.xyz.com解析到指定IP,可以使用Java 9引入的InetAddressResolverProvider实现全局自定义DNS:

import java.net.InetAddress;
import java.net.InetAddressResolver;
import java.net.InetAddressResolverProvider;
import java.net.UnknownHostException;
import java.util.Collections;
import java.util.concurrent.CompletionStage;

public class CustomDnsProvider extends InetAddressResolverProvider {
    @Override
    public InetAddressResolver get(Configuration configuration) {
        return new InetAddressResolver() {
            // 复用默认解析器处理其他域名
            private final InetAddressResolver defaultResolver = InetAddressResolverProvider.provider().get(configuration);

            @Override
            public CompletionStage<java.util.List<InetAddress>> lookupByName(String host, LookupPolicy lookupPolicy) {
                if ("abc.xyz.com".equals(host)) {
                    try {
                        InetAddress customAddr = InetAddress.getByAddress(host, new byte[]{100, 70, 125, 57});
                        return java.util.concurrent.CompletableFuture.completedFuture(Collections.singletonList(customAddr));
                    } catch (UnknownHostException e) {
                        return java.util.concurrent.CompletableFuture.failedFuture(e);
                    }
                }
                return defaultResolver.lookupByName(host, lookupPolicy);
            }

            @Override
            public CompletionStage<String> lookupByAddress(byte[] addr) {
                return defaultResolver.lookupByAddress(addr);
            }
        };
    }

    @Override
    public String name() {
        return "custom-fqdn-resolver";
    }
}

启动JVM时添加参数,注册自定义解析器:

java -Djava.net.spi.nameservice.provider.1=custom,com.yourpackage.CustomDnsProvider YourMainClass

注意:此方法会全局生效,影响所有域名解析,仅在必要时使用。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 15:33:16