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

Android 9 Pie中Volley出现SSLHandshakeException问题求助

解决Android 9 Pie中Volley的SSL握手错误

你遇到的SSLHandshakeException本质是Android 9(API 28)开始默认严格校验HTTPS证书的合法性,你的服务器证书不在系统信任的根证书列表里(比如是自签名证书),所以即使配置了android:usesCleartextTraffic="true"也没用——这个配置只是允许明文HTTP请求,和HTTPS的证书验证完全无关。

下面给你几种解决方案,按推荐程度排序:

方案一:使用受信任的CA证书(生产环境必选)

如果你的应用要上线,最安全合规的方式是给服务器部署由公共可信CA机构颁发的SSL证书(比如Let's Encrypt的免费证书),这样Android系统会自动信任该证书,不需要额外修改代码。

方案二:自定义信任管理器,信任特定证书(测试环境用)

如果是测试环境使用的自签名证书,你可以让Volley专门信任这个特定证书:

步骤1:准备证书文件

把你的服务器SSL证书(.crt格式)放到项目的res/raw目录下(如果没有raw文件夹,直接在res目录下新建一个即可)。

步骤2:创建自定义SSL工具类

添加一个工具类来生成信任指定证书的SSLSocketFactory:

import android.content.Context;
import android.util.Log;
import java.io.InputStream;
import java.security.KeyStore;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManagerFactory;

public class SSLUtils {
    public static SSLSocketFactory getSSLSocketFactory(Context context, int certRawResId) {
        try {
            CertificateFactory cf = CertificateFactory.getInstance("X.509");
            InputStream certInputStream = context.getResources().openRawResource(certRawResId);
            Certificate certificate;
            try {
                certificate = cf.generateCertificate(certInputStream);
                Log.d("SSLUtils", "证书加载成功: " + certificate);
            } finally {
                certInputStream.close();
            }

            KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
            keyStore.load(null, null);
            keyStore.setCertificateEntry("ca", certificate);

            TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
            tmf.init(keyStore);

            SSLContext sslContext = SSLContext.getInstance("TLS");
            sslContext.init(null, tmf.getTrustManagers(), null);
            return sslContext.getSocketFactory();
        } catch (Exception e) {
            Log.e("SSLUtils", "创建SSLSocketFactory失败", e);
            return null;
        }
    }
}

步骤3:修改Volley请求队列的初始化

在创建RequestQueue时,使用自定义的HurlStack来配置我们的SSLSocketFactory:

private void test() {
    StringRequest stringRequest = new StringRequest(Request.Method.POST, url_registration,
            new Response.Listener<String>() {
                @Override
                public void onResponse(String response) {
                    // 处理响应数据
                }
            }, new Response.ErrorListener() {
                @Override
                public void onErrorResponse(VolleyError error) {
                    pDialog.dismiss();
                    Log.e("Err*********>", error.toString());
                }
            }) {
        @Override
        protected Map<String, String> getParams() {
            Map<String, String> params = new HashMap<>();
            // 添加你的请求参数
            return params;
        }
    };

    // 初始化带自定义SSL配置的RequestQueue
    SSLSocketFactory sslSocketFactory = SSLUtils.getSSLSocketFactory(this, R.raw.your_certificate);
    HurlStack hurlStack = new HurlStack(null, sslSocketFactory);
    RequestQueue requestQueue = Volley.newRequestQueue(this, hurlStack);
    requestQueue.add(stringRequest);
}

记得把代码中的R.raw.your_certificate替换成你实际的证书资源ID。

方案三:完全忽略证书验证(不推荐,仅临时测试用)

这种方式会跳过所有证书验证,非常不安全,绝对不能用于生产环境,只适合本地临时测试场景:

// 工具类生成忽略证书校验的SSLSocketFactory
public static SSLSocketFactory getUnsafeSSLSocketFactory() {
    try {
        SSLContext sslContext = SSLContext.getInstance("TLS");
        sslContext.init(null, new TrustManager[]{
            new X509TrustManager() {
                @Override
                public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) {}

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

                @Override
                public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                    return new java.security.cert.X509Certificate[]{};
                }
            }
        }, new SecureRandom());
        return sslContext.getSocketFactory();
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}

然后同样在初始化RequestQueue时传入这个SSLSocketFactory即可。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.13 08:09:12