OkHttp 基础配置:引入库与 SSL/TLS 参数设置
好,咱们正式开始动手了。这一章我带你走一遍 OkHttp 的基础配置流程。说白了,就是让我们的 App 能安全地跟服务器握手。我个人习惯先把网络库的底子打好,后面加什么证书锁定、双向认证都顺理成章。
1. 引入 OkHttp 库
首先,你得把 OkHttp 请进项目。在 build.gradle 里加上依赖就行。我建议用最新稳定版,但别追太新,有时候新版本会改 API,反而踩坑。
dependencies {
implementation 'com.squareup.okhttp3:okhttp:4.12.0'
implementation 'com.squareup.okhttp3:logging-interceptor:4.12.0'
}
嗯,这里要注意:logging-interceptor 不是必须的,但我强烈建议加上。调试 SSL 握手时,它能帮你看到请求头和证书信息,省得你抓瞎。
2. 创建 OkHttpClient 实例
OkHttp 的核心就是 OkHttpClient。我习惯用 Builder 模式来构造,这样每个参数都看得清清楚楚。
OkHttpClient client = new OkHttpClient.Builder()
.connectTimeout(30, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS)
.writeTimeout(30, TimeUnit.SECONDS)
.build();
你想想看,超时时间设太短,网络波动一下请求就断了;设太长,用户等得心焦。30 秒是我在多个项目里试出来的平衡点。当然,如果你做的是实时性要求高的场景,比如视频通话,那得再调小。
3. 配置 SSL/TLS 基本参数
接下来是重头戏。SSL/TLS 配置说白了就是三件事:信任什么证书、支持什么协议、用什么加密套件。
3.1 指定 TLS 版本
我记得 Android 4.x 时代还在用 SSLv3,那玩意儿早被攻破了。现在最低也得 TLS 1.2。我一般这么写:
ConnectionSpec spec = new ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS)
.tlsVersions(TlsVersion.TLS_1_2, TlsVersion.TLS_1_3)
.cipherSuites(
CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384)
.build();
OkHttpClient client = new OkHttpClient.Builder()
.connectionSpecs(Collections.singletonList(spec))
.build();
为什么只列这四个加密套件?因为它们是目前业界公认安全且性能不错的。我曾经见过有人把几十个套件全列上,结果握手时协商了一个弱套件,反而降低了安全性。少即是多,你想想看。
ConnectionSpec.COMPATIBLE_TLS,它为了兼容老服务器会包含一些弱加密套件。除非你对接的服务器实在升级不了,否则别妥协。
3.2 自定义信任管理器
默认情况下,OkHttp 信任系统根证书。但如果你要对接自签名证书,或者做证书锁定,就得自己写 TrustManager。这里我展示一个最基础的——信任一个特定的自签名证书:
// 加载你的证书文件(放在 res/raw 或 assets 下)
CertificateFactory cf = CertificateFactory.getInstance("X.509");
InputStream caInput = context.getResources().openRawResource(R.raw.my_cert);
Certificate ca;
try {
ca = cf.generateCertificate(caInput);
} finally {
caInput.close();
}
// 创建 KeyStore 并添加证书
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(null, null);
keyStore.setCertificateEntry("ca", ca);
// 创建 TrustManager
TrustManagerFactory tmf = TrustManagerFactory.getInstance(
TrustManagerFactory.getDefaultAlgorithm());
tmf.init(keyStore);
// 构建 SSLContext
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, tmf.getTrustManagers(), null);
// 应用到 OkHttpClient
OkHttpClient client = new OkHttpClient.Builder()
.sslSocketFactory(sslContext.getSocketFactory(),
(X509TrustManager) tmf.getTrustManagers()[0])
.build();
这段代码我几乎每个项目都会写一遍,但每次都要小心那个 X509TrustManager 的强转。如果你传错了类型,运行时直接崩溃。嗯,这里要注意。
4. 知识体系总览
为了让你看得更清楚,我画了一张图,把 OkHttp 的 SSL/TLS 配置脉络梳理了一下:
5. 验证配置是否生效
配置完了,怎么知道它真的在走 TLS 1.2?我教你一个土办法:加一个网络拦截器,打印出连接信息。
client = client.newBuilder()
.addInterceptor(chain -> {
Request request = chain.request();
Response response = chain.proceed(request);
// 注意:这里拿不到 TLS 版本,但可以看响应头
System.out.println("Response: " + response.code());
return response;
})
.build();
更靠谱的做法是用 logging-interceptor 配合 HttpLoggingInterceptor.Level.HEADERS。你会看到类似这样的输出:
--> TLS 1.2, ECDHE_RSA_WITH_AES_128_GCM_SHA256
--> HEADERS
Content-Type: application/json
...
看到那行 TLS 1.2 和加密套件名,就说明配置生效了。我曾经在调试一个金融类 App 时,发现服务器只支持 TLS 1.0,客户端却强制要求 1.2,结果握手失败。最后跟服务器团队协调升级才解决。所以,配置前最好先确认服务器支持什么版本。
6. 常见问题与避坑
- javax.net.ssl.SSLHandshakeException:通常是证书不信任或 TLS 版本不匹配。检查你的 TrustManager 和 ConnectionSpec。
- NoSuchAlgorithmException:Android 版本太老,不支持 TLS 1.3。我建议最低支持到 API 16,但 TLS 1.3 需要 API 28+。所以代码里要同时写 TLS 1.2 和 1.3。
- Socket closed:超时时间太短,或者服务器主动断连。先调大超时试试。
好,这一章就到这里。你跟着把代码敲一遍,跑通一个 HTTPS 请求,就算入门了。下一章我们聊证书锁定,那才是真正防中间人攻击的硬菜。