一、请求创建:OkHttpClient 的初始化与配置
OkHttp 的请求创建过程如同组装一台精密仪器,每个组件都有明确分工:
1.1 OkHttpClient 的默认配置
java
OkHttpClient client = new OkHttpClient(); // 直接创建使用默认配置
默认配置通过 Builder 模式初始化,关键参数包括:
- Dispatcher:请求调度器,控制并发请求(默认最大 64 个异步请求,每个主机最多 5 个)
- 连接池:复用 TCP 连接,默认保持 5 分钟(
new ConnectionPool()) - 超时时间:连接 10 秒,读写各 10 秒
- 拦截器链:预设 5 个核心拦截器,加上用户自定义拦截器
1.2 Request 的构建与校验
java
Request request = new Request.Builder()
.url("https://www.baidu.com")
.get() // 内部调用method("GET", null)
.addHeader("User-Agent", "OkHttp/3.14.7")
.build();
构建过程中会进行严格校验:
- GET 请求不允许携带请求体(
HttpMethod.permitsRequestBody(method)) - URL 自动转换(WebSocket 的 ws:// 转为 http://)
- 请求头名称不允许为空(
addHeader方法校验)
二、请求调度:Dispatcher 的并发控制机制
OkHttp 的调度器如同快递分拣中心,高效管理请求队列:
2.1 同步请求流程
java
Response response = client.newCall(request).execute(); // 同步请求
核心步骤:
- 状态校验:检查请求是否已执行(
executed标志位) - 调度记录:将请求加入
runningSyncCalls队列 - 拦截器链执行:调用
getResponseWithInterceptorChain()处理请求 - 请求结束:从队列移除请求(
dispatcher.finished())
2.2 异步请求流程
java
client.newCall(request).enqueue(callback); // 异步请求
异步调度更复杂,类似快递分拣的优先级处理:
-
队列管理:请求先放入
readyAsyncCalls等待队列 -
并发控制:
- 总异步请求数超过 64 个则等待
- 同一主机请求超过 5 个则等待
-
线程池执行:使用类似 CachedThreadPool 的线程池(
executorService) -
状态回收:请求结束后调用
promoteAndExecute()释放资源,调度等待队列中的请求
2.3 并发控制示例
java
// Dispatcher的promoteAndExecute方法核心逻辑
for (AsyncCall call : readyAsyncCalls) {
if (runningAsyncCalls.size() >= 64) break; // 总并发限制
if (call.callsPerHost() >= 5) continue; // 主机并发限制
readyAsyncCalls.remove(call);
runningAsyncCalls.add(call);
call.executeOn(executorService); // 放入线程池执行
}
三、请求执行:拦截器链的流水线处理
拦截器链是 OkHttp 的灵魂,其工作原理类似汽车组装流水线,每个环节处理特定任务:
3.1 拦截器链的组成
java
List<Interceptor> interceptors = new ArrayList<>();
interceptors.addAll(client.interceptors()); // 用户自定义应用拦截器
interceptors.add(new RetryAndFollowUpInterceptor()); // 重试拦截器
interceptors.add(new BridgeInterceptor()); // 桥接拦截器
interceptors.add(new CacheInterceptor()); // 缓存拦截器
interceptors.add(new ConnectInterceptor()); // 连接拦截器
interceptors.addAll(client.networkInterceptors()); // 用户自定义网络拦截器
interceptors.add(new CallServerInterceptor()); // 服务器请求拦截器
3.2 拦截器执行流程
拦截器链采用责任链模式,每个拦截器处理请求后调用下一个拦截器:
java
// RealInterceptorChain的proceed方法
Response proceed(Request request) {
// 获取当前拦截器
Interceptor interceptor = interceptors.get(index);
// 创建下一个拦截器链(index+1)
RealInterceptorChain next = new RealInterceptorChain(interceptors, index+1, ...);
// 调用当前拦截器的intercept方法,传入下一个链
return interceptor.intercept(next);
}
3.3 核心拦截器功能解析
| 拦截器名称 | 核心功能类比 | 实际作用 |
|---|---|---|
| 应用拦截器 | 快递揽收员添加备注 | 添加自定义 Header、通用参数加密、请求日志记录 |
| RetryAndFollowUpInterceptor | 快递错误处理中心 | 处理网络错误重试(如连接失败)、自动处理 3xx 重定向 |
| BridgeInterceptor | 快递包装流水线 | 添加 Cookie、Content-Type 等基础 Header,处理 Gzip 压缩响应 |
| CacheInterceptor | 快递仓库管理员 | 检查缓存是否可用,避免重复网络请求,更新缓存数据 |
| ConnectInterceptor | 快递运输调度中心 | 管理连接池,复用 TCP 连接,创建 Socket 通信 |
| 网络拦截器 | 快递运输监控系统 | 监控网络层数据传输,可获取原始网络请求和响应 |
| CallServerInterceptor | 快递最终配送员 | 真正发起网络请求,处理 Socket 读写,获取服务器响应 |
四、实战理解:拦截器链的执行时序
以访问百度为例,拦截器链的执行过程如下:
-
应用拦截器:添加自定义日志
java
client.newCall(request).enqueue(new Callback() { @Override public void onResponse(Call call, Response response) { Log.d("OkHttp", "应用拦截器:请求开始"); } }); -
RetryAndFollowUpInterceptor:处理可能的重试
- 若 DNS 解析失败,尝试其他 IP 地址
- 遇到 401 Unauthorized,自动添加认证信息重试
-
BridgeInterceptor:包装请求头
- 添加
Host: www.baidu.com - 自动处理 Cookie(如 Set-Cookie 响应头)
- 添加
-
CacheInterceptor:检查本地缓存
- 若缓存有效(如
max-age未过期),直接返回缓存数据 - 否则发起网络请求,并更新缓存
- 若缓存有效(如
-
ConnectInterceptor:建立网络连接
- 从连接池获取可用连接(如同一主机的现有 TCP 连接)
- 若没有则创建新连接(三次握手)
-
网络拦截器:监控网络数据
- 可获取原始 Socket 发送的 HTTP 请求报文
- 监控响应数据的字节流
-
CallServerInterceptor:真正发送请求
- 通过 Socket 发送请求数据
- 读取服务器响应,处理 HTTP/2 帧数据
五、核心设计模式解析
OkHttp 的高性能源于其精妙的设计模式应用:
-
建造者模式:OkHttpClient 和 Request 的构建
java
OkHttpClient client = new OkHttpClient.Builder() .connectTimeout(15, SECONDS) .addInterceptor(new LogInterceptor()) .build(); -
责任链模式:拦截器链的实现
- 每个拦截器无需知道下一个拦截器是谁,只需处理自己的任务
- 解耦各功能模块,便于扩展(如添加自定义拦截器)
-
工厂模式:RealCall 的创建
java
Call call = client.newCall(request); // 工厂方法创建具体实现类 -
单例模式:OkHttpClient 的推荐用法
java
// 全局唯一实例,复用连接池和配置 public static final OkHttpClient CLIENT = new OkHttpClient.Builder()...build();
六、性能优化关键点
理解 OkHttp 工作流程后,可针对性进行性能优化:
-
连接池优化:
java
// 保持100个连接,存活5分钟 .connectionPool(new ConnectionPool(100, 5, TimeUnit.MINUTES)) -
缓存策略:
java
// 500MB磁盘缓存 .cache(new Cache(context.getCacheDir(), 500 * 1024 * 1024)) -
拦截器顺序:
- 应用拦截器优先于网络拦截器
- 缓存拦截器在网络请求前处理
-
超时设置:
java
.connectTimeout(10, SECONDS) // 连接超时 .readTimeout(30, SECONDS) // 读取超时
七、总结:OkHttp 的设计哲学
OkHttp 的工作流程体现了 "可扩展管道架构" 的设计思想:
-
模块化:每个拦截器专注解决一个问题(重试、缓存、连接等)
-
可扩展:通过自定义拦截器无缝介入请求流程
-
高性能:连接池、缓存、HTTP/2 等技术减少网络开销
-
鲁棒性:自动处理网络异常、重定向、认证等复杂场景
理解这一流程后,开发者可更好地:
-
自定义拦截器实现特殊需求(如全局 Header、参数加密)
-
优化网络请求性能(连接池、缓存策略)
-
定位网络问题(通过拦截器打印详细日志)
OkHttp 的拦截器机制如同为网络请求搭建了一条可定制的 "高速公路",而开发者就是这条路上的规划师,通过合理配置和扩展,打造高性能的网络请求系统。