本地环境下服务器与Android客户端HTTPS通信配置问题排查
解决Android模拟器访问本地HTTPS服务器的SSL握手错误
别慌,这个SSLHandshakeException本质就是Android系统不信任你自己生成的自签名证书——哪怕你加了CertificatePinner,证书钉住的前提是证书本身被系统信任,不然验证链还是断的。而且你是本地练习项目,完全可以搞定,给你两个靠谱的方案:
方案一:把自签名证书导入Android模拟器(更贴近正式环境逻辑)
这个方法是让模拟器真正信任你的服务器证书,步骤很简单:
从p12导出单独的证书文件
用keytool命令把你的p12证书里的公钥导出成Android能识别的格式:keytool -exportcert -alias sampleName -keystore resources/keystore/sampleName.p12 -storetype PKCS12 -storepass samplePassword -file server_cert.cer执行完会生成一个
server_cert.cer文件。把证书传到模拟器里
用adb命令把证书推到模拟器的存储:adb push server_cert.cer /sdcard/在模拟器里手动安装证书
打开模拟器的设置 → 安全 → 加密与凭据 → 从存储安装,找到刚才推的server_cert.cer,随便起个名字(比如MyLocalServer),然后选择VPN和应用用途完成安装。安装完重启下你的Android应用,再发请求应该就能正常握手了。
方案二:配置OkHttp跳过证书验证(仅本地练习用!正式环境绝对禁用)
如果不想手动装证书图省事,就给OkHttp加个自定义的信任管理器,让它接受所有证书(仅限练习,正式环境这么做等于裸奔)。修改你的OkHttpClient代码:
// 注意:仅用于本地练习项目,正式生产环境严禁使用! val trustAllCerts = arrayOf<TrustManager>(object : X509TrustManager { override fun checkClientTrusted(chain: Array<out X509Certificate>?, authType: String?) {} override fun checkServerTrusted(chain: Array<out X509Certificate>?, authType: String?) {} override fun getAcceptedIssuers(): Array<X509Certificate> = emptyArray() }) // 创建自定义SSL上下文 val sslContext = SSLContext.getInstance("TLS") sslContext.init(null, trustAllCerts, SecureRandom()) val sslSocketFactory = sslContext.socketFactory // 构建OkHttpClient val httpClient = OkHttpClient.Builder() .certificatePinner( CertificatePinner.Builder() // 注意:这里的host不要带https://,只写IP+端口即可 .add("10.0.2.2:8080", "sha256/lVIcG+gpmlabsq1bW5RbvB+kqVSHKdOFyoxjo9+SLEs=") .build() ) .sslSocketFactory(sslSocketFactory, trustAllCerts[0] as X509TrustManager) .hostnameVerifier { _, _ -> true } // 忽略主机名验证,因为是本地IP .build()
额外注意点
- 你之前的
CertificatePinner里写的是"https://10.0.2.2:8080",这个格式不对!应该去掉https://,只保留"10.0.2.2:8080",不然钉住的主机和实际请求的主机不匹配,也会导致验证失败。 - 再确认下服务器端的
application.properties配置:路径、密码、别名必须和你生成p12证书时完全一致,比如server.ssl.key-store=classpath:keystore/sampleName.p12要确保这个文件确实在resources/keystore目录下。
本地环境完全可以实现这个功能,放心折腾就行,毕竟是练习项目,怎么方便怎么来~
内容的提问来源于stack exchange,提问作者David Holkup




