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

Android 6(API23)使用OkHttp出现SSLHandshakeException问题求助

解决Android 6(API23)上OkHttp的证书信任异常问题

嘿,我刚帮朋友搞定过几乎一模一样的问题!作为网络新手碰到这种证书错误确实头大,我给你拆解下原因和靠谱的解决方案:

为什么会出现这个问题?

Android 7(API24)及以上系统在证书信任机制上做了优化,比如会自动补全不完整的服务器证书链;但Android 6及以下系统没这个能力,如果你的服务器配置的证书链不完整(比如缺了中间证书),或者用了Android 6默认根证书库里没有的根证书,就会触发这个CertPathValidatorException。

另外如果你的OkHttp版本太高,在旧系统上也可能有适配小问题,但先从证书本身排查更靠谱。

解决方案(按优先级排序)

1. 修复服务器的证书链(最推荐,生产环境必用)

这是从根源解决问题的方法。你可以用SSL检测工具检查服务器的证书链是否完整——如果工具提示“证书链不完整”,联系服务器管理员补上缺失的中间证书就行。补全后,Android 6就能正常信任服务器证书,不用改App代码。

2. 给OkHttp添加自定义信任管理器(适合测试/临时方案)

如果暂时没法修改服务器,或者只是测试用,可以让OkHttp专门信任你的服务器证书。步骤如下:

第一步:导出服务器证书

  • 用浏览器打开你的服务器地址,点击地址栏的锁图标,导出证书(格式选X.509)
  • 把导出的证书文件放到App的res/raw目录下(没有raw目录就自己创建一个)

第二步:修改OkHttp的配置

在创建OkHttpClient的时候,加载证书并设置信任管理器:

// 加载raw目录里的证书文件(替换成你的证书文件名)
InputStream certInputStream = getResources().openRawResource(R.raw.your_server_cert);
CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
X509Certificate serverCert = (X509Certificate) certFactory.generateCertificate(certInputStream);

// 初始化KeyStore,把证书存进去
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(null, null);
keyStore.setCertificateEntry("server_cert", serverCert);

// 创建信任管理器
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(keyStore);
TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();

// 配置OkHttpClient
OkHttpClient okHttpClient = new OkHttpClient.Builder()
        .sslSocketFactory(new SSLSocketFactoryCompat(serverCert), (X509TrustManager) trustManagers[0])
        .build();

补充:兼容Android 6的SSLSocketFactoryCompat

因为Android 6的SSLSocketFactory有一些限制,你需要写一个兼容类:

public class SSLSocketFactoryCompat extends SSLSocketFactory {
    private final SSLSocketFactory delegate;

    public SSLSocketFactoryCompat(X509Certificate cert) throws NoSuchAlgorithmException, KeyManagementException {
        SSLContext sslContext = SSLContext.getInstance("TLS");
        sslContext.init(null, new TrustManager[]{new X509TrustManager() {
            @Override
            public void checkClientTrusted(X509Certificate[] chain, String authType) {}

            @Override
            public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
                // 验证服务器证书是否和我们导入的一致
                for (X509Certificate c : chain) {
                    if (c.equals(cert)) {
                        return;
                    }
                }
                throw new CertificateException("Unknown server certificate");
            }

            @Override
            public X509Certificate[] getAcceptedIssuers() {
                return new X509Certificate[0];
            }
        }}, null);
        delegate = sslContext.getSocketFactory();
    }

    @Override
    public String[] getDefaultCipherSuites() {
        return delegate.getDefaultCipherSuites();
    }

    @Override
    public String[] getSupportedCipherSuites() {
        return delegate.getSupportedCipherSuites();
    }

    @Override
    public Socket createSocket() throws IOException {
        return delegate.createSocket();
    }

    @Override
    public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException {
        return delegate.createSocket(s, host, port, autoClose);
    }

    @Override
    public Socket createSocket(String host, int port) throws IOException, UnknownHostException {
        return delegate.createSocket(host, port);
    }

    @Override
    public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException, UnknownHostException {
        return delegate.createSocket(host, port, localHost, localPort);
    }

    @Override
    public Socket createSocket(InetAddress host, int port) throws IOException {
        return delegate.createSocket(host, port);
    }

    @Override
    public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException {
        return delegate.createSocket(address, port, localAddress, localPort);
    }
}

3. 绝对不要做的事!

别用网上那种“信任所有证书”的代码(比如跳过所有证书验证),那样会让你的App暴露在中间人攻击的风险里,生产环境绝对禁止这么做!


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 06:52:43