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
相关产品推荐
相关产品推荐

