You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android中OkHttp复用连接避免重复SSL握手的配置方法

问题描述

概述

使用的OkHttp版本为com.squareup.okhttp3:okhttp:4.9.3,交易发生时需一次性执行多个HttpRequest,采用单例OkHttpClient复用客户端,避免重复创建。

场景

同一单例OkHttpClient并行执行多个HTTP请求时,仅第一个请求触发SSL握手,其余请求不会。

问题核心

若两个请求间隔超过30秒,每次都会触发SSL握手。希望仅第一次请求执行SSL握手,即使间隔一段时间后再发请求,也不触发握手。当前无延迟并行请求正常,间隔30秒以上则触发。询问是否可通过OkHttpClient设置增加请求间的空闲超时,避免重复SSL握手。

现有代码

public class OkHttpSingleton {

private static OkHttpSingleton singletonInstance;

// No need to be static; OkHttpSingleton is unique so is this.
private OkHttpClient httpClient;
int timeoutConnect = 45000;
int timeoutSocket = 45000;


// Private so that this cannot be instantiated.
private OkHttpSingleton() {
    try {
        String tlsVersion = "TLSv1.2";
        if (android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
            tlsVersion = "TLSv1";
        }
        SSLContext sslContext = SSLContext.getInstance(tlsVersion);
        sslContext.init(null, null, null);
        SSLSocketFactory socketFactory = sslContext.getSocketFactory();

        httpClient = new OkHttpClient.Builder()
                .retryOnConnectionFailure(true)
                .connectTimeout(timeoutConnect, TimeUnit.SECONDS)
                .writeTimeout(timeoutSocket, TimeUnit.SECONDS)
                .readTimeout(timeoutSocket, TimeUnit.SECONDS)
                .sslSocketFactory(socketFactory, new X509TrustManager() {
                    @Override
                    public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {

                    }

                    @Override
                    public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {

                    }

                    @Override
                    public X509Certificate[] getAcceptedIssuers() {
                        return new X509Certificate[0];
                    }
                })
                .build();
    } catch (Exception e) {
        e.printStackTrace();
    }
}

public static OkHttpSingleton getInstance() {
    if (singletonInstance == null) {
        singletonInstance = new OkHttpSingleton();
    }
    return singletonInstance;
}

// In case you just need the unique OkHttpClient instance.
public OkHttpClient getClient() {
    return httpClient;
}

public void closeConnections() {
    httpClient.dispatcher().cancelAll();
}
}

相关截图

  • 需避免的SSL握手(Client Hello阶段):
    Client Hello和SSL握手截图
  • 服务器30秒无活动后发送的RST ACK:
    服务器RST ACK截图
解决方案

OkHttp默认连接池的空闲连接超时时间为30秒,这正是你遇到问题的原因。要解决这个问题,需要通过ConnectionPool配置延长空闲连接的存活时间,具体操作如下:

  1. 配置自定义连接池
    在OkHttpClient构建时,添加connectionPool()配置,设置更长的空闲超时时间(建议大于服务器端的连接超时时间,比如5分钟),同时可根据业务需求调整最大空闲连接数。

  2. 修改现有代码
    在OkHttpSingleton构造函数中,为OkHttpClient.Builder添加自定义ConnectionPool:

// 添加到Builder配置前
ConnectionPool connectionPool = new ConnectionPool(
        5, // 最大空闲连接数,可根据并发量调整
        5, // 空闲连接存活时间,单位:分钟
        TimeUnit.MINUTES);

httpClient = new OkHttpClient.Builder()
        // 保留原有所有配置
        .connectionPool(connectionPool) // 新增连接池配置
        .build();
  1. 关键说明

    • 客户端设置的空闲超时时间必须大于等于服务器端的连接超时时间,否则服务器主动断开连接后,客户端无法复用连接。从截图看服务器30秒无活动就发送RST ACK,所以客户端空闲时间建议设为1分钟以上。
    • 最大空闲连接数根据实际并发请求量调整,避免过多空闲连接占用资源。
  2. 额外注意
    如果调整客户端连接池后仍出现重复握手,需要确认服务器端是否有强制的连接超时策略,此时需与服务器运维人员沟通,延长服务器端的连接空闲超时时间,才能彻底解决问题。

内容的提问来源于stack exchange,提问作者KK_07k11A0585

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 00:26:36