无法从PHP获取echo值到MyResultTextView,遇Volley SSL握手错误
解决Volley的SSLHandshakeException证书信任问题
兄弟,这个SSL握手错误我太熟了!本质就是你的Android App不信任目标PHP服务器的SSL证书,导致Volley在建立HTTPS连接时直接失败了。下面给你分场景提供两种靠谱的解决办法:
方法一:自定义信任所有证书(仅测试环境用!)
如果你只是在测试阶段图方便,不想折腾证书导入,可以用这个方法——但千万不要在生产环境用,这等于放弃HTTPS的安全防护,容易被中间人攻击。
首先写一个SSL工具类:
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 SSLUtils { public static void disableSSLCertificateChecking() { try { TrustManager[] trustAllCerts = new TrustManager[]{ new X509TrustManager() { public X509Certificate[] getAcceptedIssuers() { return null; } public void checkClientTrusted(X509Certificate[] certs, String authType) {} public void checkServerTrusted(X509Certificate[] certs, String authType) {} } }; SSLContext sc = SSLContext.getInstance("TLS"); sc.init(null, trustAllCerts, new java.security.SecureRandom()); HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory()); } catch (Exception e) { e.printStackTrace(); } } }
然后在初始化Volley请求队列前调用这个方法:
// 先禁用证书校验(仅测试!) SSLUtils.disableSSLCertificateChecking(); // 正常初始化Volley队列 RequestQueue queue = Volley.newRequestQueue(context); // 发起请求获取PHP的echo值 StringRequest request = new StringRequest(Request.Method.GET, "你的PHP接口地址", response -> { // 这里就能拿到yes/no,直接设置到TextView MyResultTextView.setText(response); }, error -> error.printStackTrace()); queue.add(request);
方法二:导入服务器证书到项目(生产环境推荐)
这是正规安全的做法,让App只信任你指定的服务器证书,既解决握手问题,又保证HTTPS的安全性。
- 获取服务器证书:用浏览器访问你的PHP服务器地址,点击地址栏的锁图标,导出证书为
.crt格式(比如命名为server.crt)。 - 放入项目目录:把证书放到
res/raw文件夹下(没有raw目录就新建一个)。 - 写自定义SSLSocketFactory:
import android.content.Context; import android.util.Log; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSocketFactory; import javax.net.ssl.TrustManagerFactory; import java.io.InputStream; import java.security.KeyStore; import java.security.cert.Certificate; import java.security.cert.CertificateFactory; public class CustomSSLSocketFactory { public static SSLSocketFactory getSSLSocketFactory(Context context) { try { CertificateFactory cf = CertificateFactory.getInstance("X.509"); InputStream certInputStream = context.getResources().openRawResource(R.raw.server); Certificate ca; try { ca = cf.generateCertificate(certInputStream); } finally { certInputStream.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); return sslContext.getSocketFactory(); } catch (Exception e) { Log.e("CustomSSLSocket", "创建SSL工厂失败", e); return null; } } }
- 给Volley配置自定义SSL:
// 获取自定义的SSL工厂 SSLSocketFactory sslSocketFactory = CustomSSLSocketFactory.getSSLSocketFactory(context); if (sslSocketFactory != null) { HurlStack hurlStack = new HurlStack(null, sslSocketFactory); RequestQueue queue = Volley.newRequestQueue(context, hurlStack); // 发起请求 StringRequest request = new StringRequest(Request.Method.GET, "你的PHP接口地址", response -> MyResultTextView.setText(response), error -> error.printStackTrace()); queue.add(request); }
另外补充:如果你的服务器用的是正规CA颁发的证书(比如Let's Encrypt),那可能是证书链不完整,这种情况可以联系服务器管理员补全证书链,或者在客户端导入完整的证书链。
内容的提问来源于stack exchange,提问作者RAM GOPAL VARMA ALLURI
相关产品推荐
相关产品推荐

