使用SSLSocketFactory的HttpsURLConnection抛出UnknownHostException问题
解决Java调用API时的UnknownHostException异常
我尝试调用一个需要上传证书才能访问的API,编写了以下API调用方法建立连接,但运行时抛出java.net.UnknownHostException异常。已确认API地址正确且具备访问权限,证书为开发环境的.crt文件,请求解决该问题。
API调用方法
public static String consumeAPI() { String respAPI = ""; String param = "some_param"; String user = "user"; String pswrd = "pass"; try { SSLSocketFactory ssl = createSSLSocketFactory("path_of_cert"); URL url = new URL("https://api-dir.com.es:8080/api"); HttpsURLConnection conn = (HttpsURLConnection) url.openConnection(); conn.setSSLSocketFactory(ssl); conn.setDoOutput(true); conn.setRequestMethod("POST"); conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); conn.setRequestProperty("Authorization", "Basic " + Base64.getEncoder().encodeToString((user + ":" + pswrd).getBytes(StandardCharsets.UTF_8))); conn.setConnectTimeout(APIUtils.TIMEOUT); try (OutputStream os = conn.getOutputStream()) { os.write(parametros.getBytes(StandardCharsets.UTF_8)); os.flush(); if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) { try (BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream(), StandardCharsets.UTF_8))) { StringBuilder result = new StringBuilder(); String auxStr; while ((auxStr = br.readLine()) != null) { result.append(auxStr); } respAPI = result.toString(); } } } return respAPI; } catch(IOException | ClassCastException | IllegalStateException | IllegalArgumentException e) { e.printStackTrace(); return null; } }
加载证书的SSLSocketFactory生成方法
private static SSLSocketFactory createSSLSocketFactory(String certPath) { try { try (InputStream in =APIUtils.class.getResourceAsStream(certPath)) { Certificate certificate = CertificateFactory.getInstance("X.509").generateCertificate( in ); KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); keyStore.load(null); keyStore.setCertificateEntry("certalias", certificate); TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); trustManagerFactory.init(keyStore); SSLContext sslContext = SSLContext.getInstance("TLSv1.2"); sslContext.init(null, trustManagerFactory.getTrustManagers(), null); return sslContext.getSocketFactory(); } } catch(CertificateException | KeyStoreException | NoSuchAlgorithmException | IOException | KeyManagementException e) { e.printStackTrace(); return null; } }
错误堆栈信息
java.net.UnknownHostException: api-dir.com.es at java.base/sun.nio.ch.NioSocketImpl.connect(NioSocketImpl.java:567) at java.base/java.net.SocksSocketImpl.connect(SocksSocketImpl.java:327) at java.base/java.net.Socket.connect(Socket.java:633) at java.base/sun.security.ssl.SSLSocketImpl.connect(SSLSocketImpl.java:304) at java.base/sun.net.NetworkClient.doConnect(NetworkClient.java:178) at java.base/sun.net.www.http.HttpClient.openServer(HttpClient.java:532) at java.base/sun.net.www.http.HttpClient.openServer(HttpClient.java:637) at java.base/sun.net.www.protocol.https.HttpsClient.<init>(HttpsClient.java:266) at java.base/sun.net.www.protocol.https.HttpsClient.New(HttpsClient.java:380) at java.base/sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.getNewHttpClient(AbstractDelegateHttpsURLConnection.java:193) at java.base/sun.net.www.protocol.http.HttpURLConnection.plainConnect0(HttpURLConnection.java:1242) at java.base/sun.net.www.protocol.http.HttpURLConnection.plainConnect(HttpURLConnection.java:1128) at java.base/sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:179) at java.base/sun.net.www.protocol.http.HttpURLConnection.getOutputStream0(HttpURLConnection.java:1430) at java.base/sun.net.www.protocol.http.HttpURLConnection.getOutputStream(HttpURLConnection.java:1401) at java.base/sun.net.www.protocol.https.HttpsURLConnectionImpl.getOutputStream(HttpsURLConnectionImpl.java:220) at deployment.regional.war//com.ekt.regional.web.api.SomeAPI.consumeAPI(SomeAPI.java:49)
解决方案
UnknownHostException本质是DNS解析失败,和证书加载逻辑无关,按以下步骤排查:
- 测试域名解析:在运行代码的机器上执行
ping api-dir.com.es或nslookup api-dir.com.es,确认是否能解析到IP地址。如果解析失败,检查本地DNS配置,或在hosts文件中手动添加域名与IP的映射。 - 检查网络代理:如果机器使用代理,确认代理是否允许访问该域名。可尝试关闭代理测试,或在代码中设置代理:
System.setProperty("https.proxyHost", "你的代理地址"); System.setProperty("https.proxyPort", "你的代理端口"); - 确认端口可达性:用
telnet api-dir.com.es 8080或nc -zv api-dir.com.es 8080测试8080端口是否开放。 - 修正代码变量错误:调用API的代码中,定义的变量是
param,但写入流时用了parametros,需修正为param.getBytes(StandardCharsets.UTF_8),避免后续出现异常。
内容的提问来源于stack exchange,提问作者TimeToCode
相关产品推荐
相关产品推荐

