Android Studio中javax.net.ssl.SSLHandshakeException异常求助
SSL握手失败:Android Volley调用InfinityFree部署的REST API报错
我为应用创建了REST API,部署在InfinityFree平台连接MySQL数据库,网站已配置从InfinityFree获取的SSL证书。但在Android Studio项目中用Volley库调用该API时,出现如下错误,之前在000webhost部署时一切正常,请问问题出在哪里?
D/Linux: [Posix_connect Debug]Process com.abiapp.androidukk :443 W/System.err: com.android.volley.NoConnectionError: javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found. W/System.err: at com.android.volley.toolbox.NetworkUtility.shouldRetryException(NetworkUtility.java:173) W/System.err: at com.android.volley.toolbox.BasicNetwork.performRequest(BasicNetwork.java:145) W/System.err: at com.android.volley.NetworkDispatcher.processRequest(NetworkDispatcher.java:132) W/System.err: at com.android.volley.NetworkDispatcher.processRequest(NetworkDispatcher.java:111) W/System.err: at com.android.volley.NetworkDispatcher.run(NetworkDispatcher.java:90) W/System.err: Caused by: javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found. W/System.err: at com.android.org.conscrypt.SSLUtils.toSSLHandshakeException(SSLUtils.java:362) W/System.err: at com.android.org.conscrypt.ConscryptEngine.convertException(ConscryptEngine.java:1134) W/System.err: at com.android.org.conscrypt.ConscryptEngine.readPlaintextData(ConscryptEngine.java:1089) W/System.err: at com.android.org.conscrypt.ConscryptEngine.unwrap(ConscryptEngine.java:876) W/System.err: at com.android.org.conscrypt.ConscryptEngine.unwrap(ConscryptEngine.java:747) W/System.err: at com.android.org.conscrypt.ConscryptEngine.unwrap(ConscryptEngine.java:712) W/System.err: at com.android.org.conscrypt.ConscryptEngineSocket$SSLInputStream.processDataFromSocket(ConscryptEngineSocket.java:849) W/System.err: at com.android.org.conscrypt.ConscryptEngineSocket$SSLInputStream.access$100(ConscryptEngineSocket.java:722) W/System.err: at com.android.org.conscrypt.ConscryptEngineSocket.doHandshake(ConscryptEngineSocket.java:238) W/System.err: at com.android.org.conscrypt.ConscryptEngineSocket.startHandshake(ConscryptEngineSocket.java:217) W/System.err: at com.android.okhttp.internal.io.RealConnection.connectTls(RealConnection.java:196) W/System.err: at com.android.okhttp.internal.io.RealConnection.connectSocket(RealConnection.java:153) W/System.err: at com.android.okhttp.internal.io.RealConnection.connect(RealConnection.java:116) W/System.err: at com.android.okhttp.internal.http.StreamAllocation.findConnection(StreamAllocation.java:186) W/System.err: at com.android.okhttp.internal.http.StreamAllocation.findHealthyConnection(StreamAllocation.java:128) W/System.err: at com.android.okhttp.internal.http.StreamAllocation.newStream(StreamAllocation.java:97) W/System.err: at com.android.okhttp.internal.http.HttpEngine.connect(HttpEngine.java:289) W/System.err: at com.android.okhttp.internal.http.HttpEngine.sendRequest(HttpEngine.java:232) W/System.err: at com.android.okhttp.internal.huc.HttpURLConnectionImpl.execute(HttpURLConnectionImpl.java:465) W/System.err: at com.android.okhttp.internal.huc.HttpURLConnectionImpl.connect(HttpURLConnectionImpl.java:131) W/System.err: at com.android.okhttp.internal.huc.HttpURLConnectionImpl.getOutputStream(HttpURLConnectionImpl.java:262) W/System.err: at com.android.okhttp.internal.huc.DelegatingHttpsURLConnection.getOutputStream(DelegatingHttpsURLConnection.java:219) W/System.err: at com.android.okhttp.internal.huc.HttpsURLConnectionImpl.getOutputStream(HttpsURLConnectionImpl.java:30) W/System.err: at com.android.volley.toolbox.HurlStack.createOutputStream(HurlStack.java:319) W/System.err: at com.android.volley.toolbox.HurlStack.addBody(HurlStack.java:301) W/System.err: at com.android.volley.toolbox.HurlStack.addBodyIfExists(HurlStack.java:285) W/System.err: at com.android.volley.toolbox.HurlStack.setConnectionParametersForRequest(HurlStack.java:257) W/System.err: at com.android.volley.toolbox.HurlStack.executeRequest(HurlStack.java:89) W/System.err: at com.android.volley.toolbox.BasicNetwork.performRequest(BasicNetwork.java:104) W/System.err: ... 3 more W/System.err: Caused by: java.security.cert.CertificateException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found. W/System.err: at com.android.org.conscrypt.TrustManagerImpl.checkTrustedRecursive(TrustManagerImpl.java:661) W/System.err: at com.android.org.conscrypt.TrustManagerImpl.checkTrusted(TrustManagerImpl.java:510) W/System.err: at com.android.org.conscrypt.TrustManagerImpl.checkTrusted(TrustManagerImpl.java:428) W/System.err: at com.android.org.conscrypt.TrustManagerImpl.getTrustedChainForServer(TrustManagerImpl.java:356) W/System.err: at android.security.net.config.NetworkSecurityTrustManager.checkServerTrusted(NetworkSecurityTrustManager.java:94) W/System.err: at android.security.net.config.RootTrustManager.checkServerTrusted(RootTrustManager.java:90) W/System.err: at com.android.org.conscrypt.ConscryptEngineSocket$2.checkServerTrusted(ConscryptEngineSocket.java:161) W/System.err: at com.android.org.conscrypt.Platform.checkServerTrusted(Platform.java:250) W/System.err: at com.android.org.conscrypt.ConscryptEngine.verifyCertificateChain(ConscryptEngine.java:1644) W/System.err: at com.android.org.conscrypt.NativeCrypto.ENGINE_SSL_read_direct(Native Method) W/System.err: at com.android.org.conscrypt.NativeSsl.readDirectByteBuffer(NativeSsl.java:568) W/System.err: at com.android.org.conscrypt.ConscryptEngine.readPlaintextDataDirect(ConscryptEngine.java:1095) W/System.err: at com.android.org.conscrypt.ConscryptEngine.readPlaintextData(ConscryptEngine.java:1079) W/System.err: ... 29 more W/System.err: Caused by: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found. W/System.err: ... 42 more I/InputTransport: Create ARC handle: 0x78a4e05920 D/ViewRootImpl[StartActivity]: msg2 update new insets InsetsState: {mDisplayFrame=Rect(0, 0 - 1080, 2340), mSources= { InsetsSource: {mType=ITYPE_STATUS_BAR, mFrame=[0,0][1080,96], mVisible=true}, InsetsSource: {mType=ITYPE_TOP_GESTURES, mFrame=[0,0][1080,96], mVisible=true}, InsetsSource: {mType=ITYPE_LEFT_GESTURES, mFrame=[0,0][0,0], mVisible=true}, InsetsSource: {mType=ITYPE_RIGHT_GESTURES, mFrame=[0,0][0,0], mVisible=true}, InsetsSource: {mType=ITYPE_TOP_TAPPABLE_ELEMENT, mFrame=[0,0][1080,96], mVisible=true}, InsetsSource: {mType=ITYPE_LEFT_DISPLAY_CUTOUT, mFrame=[0,0][-2147483648,2340], mVisible=true}, InsetsSource: {mType=ITYPE_TOP_DISPLAY_CUTOUT, mFrame=[0,0][1080,96], mVisible=true}, InsetsSource: {mType=ITYPE_RIGHT_DISPLAY_CUTOUT, mFrame=[2147483647,0][1080,2340], mVisible=true}, InsetsSource: {mType=ITYPE_BOTTOM_DISPLAY_CUTOUT, mFrame=[0,2147483647][1080,2340], mVisible=true}, InsetsSource: {mType=ITYPE_IME, mFrame=[0,0][0,0], mVisible=false}, InsetsSource: {mType=ITYPE_SEC_IME, mFrame=[0,0][0,0], mVisible=false} }
问题原因
核心错误Trust anchor for certification path not found说明:Android系统无法识别InfinityFree提供的SSL证书的根信任机构,或者证书链配置不完整。
000webhost的证书由Android系统默认信任的CA机构签发,所以之前调用正常;而InfinityFree的证书要么是由不被Android默认信任的CA签发,要么部署时只配置了服务器证书,缺少中间证书或根证书,导致系统无法验证证书的合法性。
解决方法
1. 检查并修复InfinityFree的证书链配置
- 登录InfinityFree后台,确认下载的证书包包含完整链文件(通常包括服务器证书、中间证书、根证书)
- 重新部署证书时,将所有链文件上传并配置到服务器,不要只上传服务器证书
2. 在Android项目中添加自定义信任证书
如果证书链配置正确但Android仍不识别,可将InfinityFree的根证书导入项目:
- 从InfinityFree下载根证书(
.pem格式),重命名为certificate.pem后放到项目res/raw目录 - 创建自定义
HurlStack来信任该证书:
import android.content.Context; import android.util.Log; import com.android.volley.toolbox.HurlStack; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSocketFactory; import javax.net.ssl.TrustManager; import javax.net.ssl.TrustManagerFactory; import javax.net.ssl.X509TrustManager; import java.io.InputStream; import java.security.KeyStore; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; public class CustomHurlStack extends HurlStack { private SSLSocketFactory sslSocketFactory; public CustomHurlStack(Context context) { try { CertificateFactory cf = CertificateFactory.getInstance("X.509"); InputStream caInput = context.getResources().openRawResource(R.raw.certificate); X509Certificate ca; try { ca = (X509Certificate) cf.generateCertificate(caInput); } finally { caInput.close(); } String keyStoreType = KeyStore.getDefaultType(); KeyStore keyStore = KeyStore.getInstance(keyStoreType); keyStore.load(null, null); keyStore.setCertificateEntry("ca", ca); String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm(); TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm); tmf.init(keyStore); SSLContext sslContext = SSLContext.getInstance("TLS"); sslContext.init(null, tmf.getTrustManagers(), null); sslSocketFactory = sslContext.getSocketFactory(); } catch (Exception e) { Log.e("CustomHurlStack", e.getMessage()); } } @Override protected javax.net.ssl.HttpsURLConnection createHttpsConnection(String url) throws java.io.IOException { javax.net.ssl.HttpsURLConnection connection = (javax.net.ssl.HttpsURLConnection) super.createHttpsConnection(url); connection.setSSLSocketFactory(sslSocketFactory); return connection; } }
- 创建Volley请求队列时使用该自定义栈:
RequestQueue queue = Volley.newRequestQueue(this, new CustomHurlStack(this));
3. 临时绕过SSL验证(仅测试用,禁止生产环境使用)
如果只是测试阶段,可临时禁用SSL验证,但会带来安全风险:
import com.android.volley.toolbox.HurlStack; import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.SSLContext; import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; import java.security.cert.X509Certificate; public class UnsafeHurlStack extends HurlStack { @Override protected javax.net.ssl.HttpsURLConnection createHttpsConnection(String url) throws java.io.IOException { javax.net.ssl.HttpsURLConnection connection = (javax.net.ssl.HttpsURLConnection) super.createHttpsConnection(url); try { 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) {} @Override public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; } }}, null); connection.setSSLSocketFactory(sslContext.getSocketFactory()); } catch (Exception e) { e.printStackTrace(); } return connection; } }
- 使用方式:
RequestQueue queue = Volley.newRequestQueue(this, new UnsafeHurlStack());
内容的提问来源于stack exchange,提问作者NewbieMF
相关产品推荐
相关产品推荐

