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 握手时,它能帮你看到请求头和证书信息,省得你抓瞎。

小提示: 如果你用 Kotlin,记得检查项目是否启用了 Java 8+ 的 desugaring。OkHttp 内部用了一些 Java 8 API,不配置的话编译会报错。

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 配置脉络梳理了一下:

OkHttpClient 基础配置 超时时间 · 拦截器 · 缓存策略 TLS 版本与加密套件 TLS 1.2/1.3 · 强加密套件 · ConnectionSpec 证书信任管理 TrustManager · 自签名证书 · 证书锁定 目标:安全握手 + 防中间人攻击

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:超时时间太短,或者服务器主动断连。先调大超时试试。
核心要点: OkHttp 的 SSL/TLS 配置,本质上就是控制「信任什么」和「用什么握手」。别想着一步到位,先跑通基础配置,再逐步加固。

好,这一章就到这里。你跟着把代码敲一遍,跑通一个 HTTPS 请求,就算入门了。下一章我们聊证书锁定,那才是真正防中间人攻击的硬菜。

公众号:蓝海资料掘金营,微信 deep3321