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

Android中OkHttp3处理HTTPS链接出现SSL握手异常求助

OkHttp3 解决 HTTPS 证书路径验证失败问题

我懂你碰到的这个麻烦——用OkHttp3访问https://cbsenet.nic.in的PDF文件时触发了SSL握手异常,而另一个域名的链接却能正常工作。这个错误的核心原因是Java默认的信任库里没有该网站的根证书,导致无法验证证书链的有效性,所以抛出了PKIX path building failed的异常。

先简单说下为什么两个链接表现不同:www.ugcnetonline.in用的是主流CA机构颁发的证书,这类证书已经被Java默认信任库收录,所以OkHttp能顺利完成验证;而cbsenet.nic.in的证书要么是自签名的,要么是由不被Java默认信任的CA颁发的,自然就过不了验证这一关。

下面给你两种解决方案,分别适用于测试和生产场景:

方案一:临时绕过SSL验证(仅测试环境使用)

这个方法是让OkHttp信任所有证书,跳过验证环节,绝对不能在生产环境用,会让你的应用面临中间人攻击的风险。代码示例如下:

import javax.net.ssl.*;
import java.security.cert.X509Certificate;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;

public class OkHttpSslTest {
    public static void main(String[] args) throws Exception {
        String url1 = "https://cbsenet.nic.in/cbsenet/PDFDEC2014/Paper%20III/D-01-3.pdf";

        // 创建信任所有证书的TrustManager
        TrustManager[] trustAllCerts = new TrustManager[]{
            new X509TrustManager() {
                @Override
                public void checkClientTrusted(X509Certificate[] chain, String authType) {}

                @Override
                public void checkServerTrusted(X509Certificate[] chain, String authType) {}

                @Override
                public X509Certificate[] getAcceptedIssuers() {
                    return new X509Certificate[0];
                }
            }
        };

        // 初始化SSLContext
        SSLContext sslContext = SSLContext.getInstance("SSL");
        sslContext.init(null, trustAllCerts, new SecureRandom());

        // 忽略主机名验证
        HostnameVerifier hostnameVerifier = (hostname, session) -> true;

        // 配置OkHttpClient
        OkHttpClient client = new OkHttpClient.Builder()
            .sslSocketFactory(sslContext.getSocketFactory(), (X509TrustManager) trustAllCerts[0])
            .hostnameVerifier(hostnameVerifier)
            .build();

        // 发起请求
        Request request = new Request.Builder().url(url1).build();
        try (Response response = client.newCall(request).execute()) {
            // 这里可以处理文件下载逻辑,比如写入本地
            // response.body().byteStream();
            System.out.println("请求成功");
        }
    }
}

方案二:导入证书到信任库(生产环境推荐)

这是安全合规的做法,分为两种实现方式:

方式1:导入到Java全局信任库

  1. 下载网站证书:打开浏览器访问https://cbsenet.nic.in,点击地址栏的锁图标,查看证书详情,将证书导出为.cer格式(比如命名为cbsenet.cer)。
  2. 执行导入命令:打开终端,运行以下命令(替换<JAVA_HOME>为你的JDK安装路径,<CERT_PATH>为证书文件所在路径):
    keytool -import -trustcacerts -alias cbsenet -file <CERT_PATH>/cbsenet.cer -keystore <JAVA_HOME>/jre/lib/security/cacerts
    
    Java默认信任库的密码是changeit,输入密码后确认导入即可。
  3. 重启你的应用,此时OkHttp会自动信任该证书,无需修改代码就能正常访问url1。

方式2:在OkHttp中使用自定义信任库

如果你不想修改全局Java信任库,可以在OkHttp中单独配置信任该证书:

import javax.net.ssl.*;
import java.io.FileInputStream;
import java.security.KeyStore;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;

public class OkHttpCustomSsl {
    public static void main(String[] args) throws Exception {
        String url1 = "https://cbsenet.nic.in/cbsenet/PDFDEC2014/Paper%20III/D-01-3.pdf";
        String certPath = "path/to/your/cbsenet.cer"; // 替换为你的证书路径

        // 加载证书文件
        CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
        X509Certificate cert;
        try (FileInputStream fis = new FileInputStream(certPath)) {
            cert = (X509Certificate) certFactory.generateCertificate(fis);
        }

        // 创建包含该证书的KeyStore
        KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
        keyStore.load(null, null);
        keyStore.setCertificateEntry("cbsenet", cert);

        // 初始化TrustManagerFactory
        TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
        tmf.init(keyStore);

        // 配置SSLContext
        SSLContext sslContext = SSLContext.getInstance("TLS");
        sslContext.init(null, tmf.getTrustManagers(), new SecureRandom());

        // 构建OkHttpClient
        OkHttpClient client = new OkHttpClient.Builder()
            .sslSocketFactory(sslContext.getSocketFactory(), (X509TrustManager) tmf.getTrustManagers()[0])
            .build();

        // 发起请求
        Request request = new Request.Builder().url(url1).build();
        try (Response response = client.newCall(request).execute()) {
            // 处理文件下载
            System.out.println("请求成功,响应码:" + response.code());
        }
    }
}

这种方式只会让你的应用信任该证书,不会影响其他Java程序,非常适合生产环境使用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 09:23:58