【Android】OKHttp网络请求原理和弱网优化
1. OkHttp 网络请求原理
OkHttp 的请求过程可以分为 四个关键阶段 :
(假设你是通过 OkHttpClient.newCall(request).enqueue(callback)
发的请求)
OkHttpClient
│
▼
Dispatcher (调度器)
│
▼
RealCall (真正的Call实现)
│
▼
Interceptor Chain (拦截器责任链)
│
▼
Stream/Connection (TCP/SSL/HTTP2)
核心组件
- OkHttpClient
- 全局配置(超时、拦截器、连接池、缓存等)
- 线程安全,推荐单例。
- Dispatcher(调度器)
- 维护同步/异步请求队列
- 默认异步最大并发请求数 = 64(每个host默认5个并发)
- RealCall
- 封装了一个具体的 HTTP 调用过程。
- 同步时走
execute()
,异步时走enqueue()
。
- Interceptor Chain(拦截器链)
OkHttp 的核心,按顺序执行:- Application Interceptor (应用拦截器)
你自己加的,比如统一加 Header、埋点。 - RetryAndFollowUpInterceptor (重试&重定向)
处理失败重试、HTTP 3xx 跟随跳转。 - BridgeInterceptor (桥接拦截器)
把用户的 Request 转成可发的 HTTP Request(补默认 Header,比如 Content-Type)。 - CacheInterceptor (缓存拦截器)
负责读写缓存(符合 HTTP 缓存协议的才会生效)。 - ConnectInterceptor (连接拦截器)
找到可用的连接(可能复用连接池的 TCP/HTTP2)。 - CallServerInterceptor(发送请求 & 读取响应)。
- Application Interceptor (应用拦截器)
- 连接池(ConnectionPool)
- 复用 TCP 连接(默认 5 分钟闲置后关闭)
- 对弱网非常重要,减少 TCP/TLS 握手开销。
2. 弱网优化思路(基于 OkHttp 原理)
弱网优化要考虑 连接建立 、数据传输 、失败恢复 三方面:
(1) 减少连接开销
-
启用连接池(默认已开启)
javanew OkHttpClient.Builder() .connectionPool(new ConnectionPool(10, 5, TimeUnit.MINUTES))
提高空闲连接数和保活时间,减少频繁建连。
-
HTTP/2
如果服务端支持,启用 HTTP/2 可以一个 TCP 连接多路复用多个请求,减少弱网下握手阻塞。
-
DNS 预解析 + 缓存
弱网 DNS 解析可能很慢,可以提前解析:
javaOkHttpClient 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 分片:
httpRange: 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 、重试退避策略。
- 如果弱网还卡,可以加弱网检测配合动态参数调整。
还可以额外参考一下【淘宝移动端统一网络库的架构演进和弱网优化技术实践】