【Android】OKHttp网络请求原理和弱网优化

【Android】OKHttp网络请求原理和弱网优化


1. OkHttp 网络请求原理

OkHttp 的请求过程可以分为 四个关键阶段

(假设你是通过 OkHttpClient.newCall(request).enqueue(callback) 发的请求)

复制代码
OkHttpClient
   │
   ▼
Dispatcher (调度器)
   │
   ▼
RealCall (真正的Call实现)
   │
   ▼
Interceptor Chain (拦截器责任链)
   │
   ▼
Stream/Connection (TCP/SSL/HTTP2)

核心组件

  1. OkHttpClient
    • 全局配置(超时、拦截器、连接池、缓存等)
    • 线程安全,推荐单例。
  2. Dispatcher(调度器)
    • 维护同步/异步请求队列
    • 默认异步最大并发请求数 = 64(每个host默认5个并发)
  3. RealCall
    • 封装了一个具体的 HTTP 调用过程。
    • 同步时走 execute(),异步时走 enqueue()
  4. Interceptor Chain(拦截器链)
    OkHttp 的核心,按顺序执行:
    • Application Interceptor (应用拦截器)
      你自己加的,比如统一加 Header、埋点。
    • RetryAndFollowUpInterceptor (重试&重定向)
      处理失败重试、HTTP 3xx 跟随跳转。
    • BridgeInterceptor (桥接拦截器)
      把用户的 Request 转成可发的 HTTP Request(补默认 Header,比如 Content-Type)。
    • CacheInterceptor (缓存拦截器)
      负责读写缓存(符合 HTTP 缓存协议的才会生效)。
    • ConnectInterceptor (连接拦截器)
      找到可用的连接(可能复用连接池的 TCP/HTTP2)。
    • CallServerInterceptor(发送请求 & 读取响应)。
  5. 连接池(ConnectionPool)
    • 复用 TCP 连接(默认 5 分钟闲置后关闭)
    • 对弱网非常重要,减少 TCP/TLS 握手开销。

2. 弱网优化思路(基于 OkHttp 原理)

弱网优化要考虑 连接建立数据传输失败恢复 三方面:


(1) 减少连接开销

  • 启用连接池(默认已开启)

    java 复制代码
    new OkHttpClient.Builder()
        .connectionPool(new ConnectionPool(10, 5, TimeUnit.MINUTES))

    提高空闲连接数和保活时间,减少频繁建连。

  • HTTP/2

    如果服务端支持,启用 HTTP/2 可以一个 TCP 连接多路复用多个请求,减少弱网下握手阻塞。

  • DNS 预解析 + 缓存

    弱网 DNS 解析可能很慢,可以提前解析:

    java 复制代码
    OkHttpClient client = new OkHttpClient.Builder()
        .dns(hostname -> {
            List<InetAddress> addresses = Arrays.asList(InetAddress.getAllByName(hostname));
            return addresses; // 可做本地缓存
        })
        .build();

(2) 控制请求超时策略

弱网时默认超时可能不合适,可以分类型调整:

java 复制代码
OkHttpClient client = new OkHttpClient.Builder()
    .connectTimeout(5, TimeUnit.SECONDS)   // 建立连接超时
    .readTimeout(8, TimeUnit.SECONDS)      // 读取超时
    .writeTimeout(8, TimeUnit.SECONDS)     // 写入超时
    .retryOnConnectionFailure(true)        // 启用失败重试
    .build();
  • 短连接超时:弱网时快速放弃连接不上的 IP,走备用。
  • 读写时间略放宽:弱网传输慢,避免误判失败。

(3) 分片/断点续传

  • 大文件上传/下载弱网下易中断,建议用 Range 分片

    http 复制代码
    Range: bytes=0-1023
  • 中断后只请求剩余部分,减少重传。


(4) 降级策略

弱网下可以:

  • 压缩数据 (Gzip / WebP 图片)
    OkHttp 默认支持 Gzip 解压,服务端加 Content-Encoding: gzip 即可。
  • 减少请求次数
    合并多个小请求为一个大请求。
  • 先本地缓存/后上传
    弱网先本地存储(Room/SQLite),网络恢复后批量上传。

(5) 智能重试

默认的 RetryAndFollowUpInterceptor 只会在特定错误下重试。

你可以自定义拦截器来做指数退避重试

java 复制代码
class RetryInterceptor implements Interceptor {
    @Override
    public Response intercept(Chain chain) throws IOException {
        int tryCount = 0;
        IOException lastException;
        while (tryCount < 3) {
            try {
                return chain.proceed(chain.request());
            } catch (IOException e) {
                lastException = e;
                tryCount++;
                Thread.sleep((long) Math.pow(2, tryCount) * 500); // 500ms, 1s, 2s
            }
        }
        throw lastException;
    }
}

(6) 弱网检测 + 动态策略

可用 TrafficStats 或测速接口判断弱网,然后动态调整 OkHttp:

java 复制代码
if (isWeakNetwork()) {
    // 降低并发、延长超时
} else {
    // 正常配置
}

总结

  • OkHttp 的本质是拦截器责任链 + 连接池复用 ,弱网优化重点是减少握手、缓存结果、控制超时、重试与降级
  • 最实用的三个点:连接复用(ConnectionPool)HTTP/2重试退避策略
  • 如果弱网还卡,可以加弱网检测配合动态参数调整。

还可以额外参考一下【淘宝移动端统一网络库的架构演进和弱网优化技术实践