OkHttp网络框架设计
目录介绍
- 01.整体概述介绍
- 1.1 概述介绍
- 1.2 核心特性说明
- 1.3 技术架构概览
- 1.4 问题思考
- 02.核心架构设计
- 2.1 整体架构设计
- 2.2 整体设计思路
- 2.3 核心组件关系图
- 03.核心组件详解
- 3.1 OkHttpClient
- 3.2 Request请求封装
- 3.3 Call请求执行接口
- 3.4 Dispatcher调度器
- 3.5 拦截器机制
- 3.6 Response返回
- 04.核心流程分析
- 4.1 请求执行流程
- 4.2 连接管理流程
- 4.3 缓存处理流程
- 05.关键技术特性
- 5.1 连接池管理
- 5.2 HTTP/2支持
- 5.3 缓存机制设计
- 5.4 安全特性设计
- 5.5 SSL/TLS流程
- 06.性能优化策略
- 6.1 连接复用
- 6.2 请求合并
- 6.3 压缩传输
- 6.4 内存管理
- 07.使用示例说明
- 7.1 基本使用
- 7.2 高级配置
- 7.3 统计请求耗时
- 08.最佳实践
- 8.1 客户端复用
- 8.2 请求取消
- 8.3 错误处理
- 09.架构优势
- 9.1 设计模式应用
- 9.2 SOLID原则体现
- 9.3 性能优势
01.整体概述介绍
1.1 概述介绍
OkHttp是一个高效的HTTP客户端库,专为Android和Java应用程序设计。基于OkHttpLib模块的源码分析,详细阐述了OkHttp的架构设计、核心组件、工作流程和技术特性。避免陷入代码细节,着重理解设计思想!
1.2 核心特性说明
- 高效的HTTP/2支持:完整支持HTTP/2协议,包括连接复用、服务器推送等特性
- 连接池管理:自动管理连接池,减少连接建立的开销
- 透明的GZIP压缩:自动处理响应压缩,减少网络传输量
- 响应缓存:支持HTTP缓存,避免重复请求
- 请求/响应拦截:灵活的拦截器机制,支持请求和响应的定制化处理
- 故障恢复:自动重试机制,提高网络请求的可靠性
1.3 技术架构概览
1graph TB 2 A[应用层] --> B[OkHttpClient] 3 B --> C[Request Builder] 4 B --> D[Call Factory] 5 D --> E[RealCall] 6 E --> F[Dispatcher] 7 F --> G[拦截器链] 8 G --> H[网络层] 9 10 subgraph "拦截器链" 11 I[应用拦截器] 12 J[重试拦截器] 13 K[桥接拦截器] 14 L[缓存拦截器] 15 M[连接拦截器] 16 N[网络拦截器] 17 O[服务器调用拦截器] 18 end 19 20 G --> I 21 I --> J 22 J --> K 23 K --> L 24 L --> M 25 M --> N 26 N --> O 27
1.4 问题思考
- OkHttp设计:OkHttp整体设计思路是什么样的?request和respond分别如何设计?如何设计call请求操作?
- OkHttp同步异步:如何设计同步和异步请求?同步操作做了什么?异步操作如何处理逻辑?
- OkHttp拦截器:拦截器是如何设计的?为什么需要拦截器?拦截器如何处理拦截,和向下分发逻辑?如何做重试机制的设计?
- OkHttp缓存:如何设计缓存?什么情况下会用到网络缓存?缓存拦截器的核心思想是什么?
- OkHttp分发器:同步和异步请求的Dispatcher是如何调度的?设计的巧妙之处是什么?
- OkHttp线程池:使用了什么线程池?是如何管理线程任务?跟普通线程池使用有何区别?
02.核心架构设计
2.1 整体架构设计
OkHttp采用分层架构设计,主要包括以下几个层次:
- 应用接口层:提供简洁的API接口,包括OkHttpClient、Request、Response等
- 调度管理层:Dispatcher负责请求的调度和线程池管理
- 拦截器链层:责任链模式实现的拦截器机制
- 连接管理层:ConnectionPool管理HTTP连接的复用
- 网络传输层:底层的Socket连接和数据传输
2.2 整体设计思路
网络请求到响应大概流程图如下所示
整体设计思路大概如下所示:
- 第一步:创建OkHttpClient对象,由于创建这个对象十分复杂,因此采用builder设计模式构造
- 第二步:包装Request请求体对象,主要是存放url,header,get请求,post请求等等属性
- 第三步:通过newCall(request)去创建一个call请求
- 第四步:开始执行同步execute或者enqueue请求,这里会使用到线程池
- 第五步:添加各种拦截器,缓存拦截器,
- 第六步:处理缓存拦截,数据复用的技术逻辑
- 第七步:创建连接请求的操作,给服务端发送请求
- 第八步:获取返回response数据,这里主要是处理code和body数据
2.3 核心组件关系图
1classDiagram 2 class OkHttpClient { 3 +Dispatcher dispatcher 4 +List~Interceptor~ interceptors 5 +ConnectionPool connectionPool 6 +Cache cache 7 +newCall(Request) Call 8 } 9 10 class Request { 11 +HttpUrl url 12 +String method 13 +Headers headers 14 +RequestBody body 15 } 16 17 class Call { 18 <<interface>> 19 +execute() Response 20 +enqueue(Callback) void 21 +cancel() void 22 } 23 24 class RealCall { 25 +OkHttpClient client 26 +Request originalRequest 27 +execute() Response 28 +enqueue(Callback) void 29 } 30 31 class Dispatcher { 32 +ExecutorService executorService 33 +Deque~AsyncCall~ readyAsyncCalls 34 +Deque~AsyncCall~ runningAsyncCalls 35 +Deque~RealCall~ runningSyncCalls 36 } 37 38 class Interceptor { 39 <<interface>> 40 +intercept(Chain) Response 41 } 42 43 OkHttpClient --> Request : creates 44 OkHttpClient --> Call : newCall() 45 Call <|-- RealCall : implements 46 OkHttpClient --> Dispatcher : uses 47 RealCall --> Interceptor : uses 48
03.核心组件详解
3.1 OkHttpClient
OkHttpClient是整个框架的入口点,采用建造者模式进行配置:
1public class OkHttpClient implements Cloneable, Call.Factory, WebSocket.Factory { 2 final Dispatcher dispatcher; 3 final @Nullable Proxy proxy; 4 final List<Protocol> protocols; 5 final List<ConnectionSpec> connectionSpecs; 6 final List<Interceptor> interceptors; 7 final List<Interceptor> networkInterceptors; 8 final EventListener.Factory eventListenerFactory; 9 final ProxySelector proxySelector; 10 final CookieJar cookieJar; 11 final @Nullable Cache cache; 12 final @Nullable InternalCache internalCache; 13 final SocketFactory socketFactory; 14 final SSLSocketFactory sslSocketFactory; 15 final ConnectionPool connectionPool; 16 // ... 更多配置项 17} 18
创建OkHttpClient对象,主要是用于Api网络请求的对象。类似于初始化网络请求,可以设置超时时间,日志打印拦截器,代理,ssl校验,域名校验等等。
主要职责:
- 管理全局配置(超时、代理、SSL等)
- 创建Call对象
- 管理拦截器链
- 管理连接池和缓存
3.1.1 创建流程架构图
1flowchart TD 2 A[开始创建OkHttpClient] --> B{使用方式} 3 4 B -->|默认构造| C[new OkHttpClient] 5 B -->|Builder模式| D[new OkHttpClient.Builder] 6 7 C --> E[使用默认配置] 8 D --> F[配置各种参数] 9 10 E --> G[创建默认组件] 11 F --> H[验证配置参数] 12 13 G --> I[初始化Dispatcher] 14 H --> I 15 16 I --> J[初始化ConnectionPool] 17 J --> K[初始化SSL配置] 18 K --> L[初始化拦截器链] 19 L --> M[初始化缓存配置] 20 M --> N[初始化超时配置] 21 N --> O[初始化事件监听器] 22 O --> P[创建OkHttpClient实例] 23 24 P --> Q[客户端就绪] 25 26 style C fill:#e3f2fd 27 style D fill:#f3e5f5 28 style G fill:#e8f5e8 29 style H fill:#fff3e0 30 style Q fill:#c8e6c9 31
3.1.2 Builder模式原理
OkHttpClient采用Builder模式的主要原因:
- 参数众多:OkHttpClient有30+个配置参数
- 可选配置:大部分参数都有合理的默认值
- 不可变性:创建后的OkHttpClient实例不可修改
- 链式调用:提供流畅的API体验
- 参数验证:在build()时统一验证参数合法性
3.1.3 Builder配置流程图
1sequenceDiagram 2 participant App as 应用代码 3 participant Builder as OkHttpClient.Builder 4 participant Validator as 参数验证器 5 participant Factory as 组件工厂 6 participant Client as OkHttpClient 7 8 App->>Builder: new Builder() 9 Builder->>Builder: 初始化默认配置 10 11 loop 配置各种参数 12 App->>Builder: 设置配置项 13 Builder->>Builder: 存储配置值 14 end 15 16 App->>Builder: build() 17 Builder->>Validator: 验证配置参数 18 alt 参数无效 19 Validator-->>Builder: 抛出异常 20 Builder-->>App: 配置异常 21 else 参数有效 22 Validator-->>Builder: 验证通过 23 Builder->>Factory: 创建组件实例 24 Factory-->>Builder: 返回组件 25 Builder->>Client: new OkHttpClient(builder) 26 Client->>Client: 复制Builder配置 27 Client-->>Builder: OkHttpClient实例 28 Builder-->>App: 返回客户端 29 end 30
3.1.4 超时配置关系图
在创建对象时,连接超时,读取超时,写入超时,完整请求超时,都可以灵活配置。那么这块是如何设计的呢?
1graph TB 2 A[超时配置] --> B[callTimeout] 3 A --> C[connectTimeout] 4 A --> D[readTimeout] 5 A --> E[writeTimeout] 6 A --> F[pingInterval] 7 8 B --> G[整个请求的总超时时间] 9 C --> H[TCP连接建立超时] 10 D --> I[从服务器读取数据超时] 11 E --> J[向服务器写入数据超时] 12 F --> K[HTTP/2连接保活间隔] 13 14 G --> L[包含连接、读写、重定向等所有时间] 15 H --> M[默认10秒] 16 I --> N[默认10秒] 17 J --> O[默认10秒] 18 K --> P[默认0-不发送ping] 19 20 style A fill:#e3f2fd 21 style B fill:#ffebee 22 style C fill:#e8f5e8 23 style D fill:#fff3e0 24 style E fill:#f3e5f5 25 style F fill:#e1f5fe 26
3.2 Request请求封装
主要是封装一个Request请求体。
1Request request = new Request.Builder() 2 .url(url) 3 .addHeader("cookie","yangchong") 4 .get() 5 .build(); 6
Request类封装了HTTP请求的所有信息:
1public final class Request { 2 final HttpUrl url; 3 final String method; 4 final Headers headers; 5 final @Nullable RequestBody body; 6 final Map<Class<?>, Object> tags; 7 8 public static class Builder { 9 @Nullable HttpUrl url; 10 String method; 11 Headers.Builder headers; 12 @Nullable RequestBody body; 13 Map<Class<?>, Object> tags = Collections.emptyMap(); 14 } 15} 16
Request包括Headers和RequestBody,而RequestBody是abstract的,他的子类是有FormBody(表单提交的)和MultipartBody(文件上传),分别对应了两种不同的MIME类型。
1FormBody :"application/x-www-form-urlencoded" 2MultipartBody:"multipart/"+xxx. 3
核心特性:
- 不可变对象设计,线程安全
- 建造者模式构建
- 支持多种HTTP方法(GET、POST、PUT、DELETE等)
- 灵活的Header管理
3.3 Call请求执行接口
如何设计Call请求基于接口开发,设计了Call接口,里面主要做同步请求execute,异步请求enqueue,取消请求cancel等等。
Call类详解:有道词典翻译该类注释:调用是准备执行的请求。call可以取消。由于此对象表示单个请求/响应对(流),因此不能执行两次。
主要是HTTP请求任务封装
- 可以说我们能用到的操纵基本上都定义在这个接口里面了,可以通过Call对象来操作请求,同步请求execute,异步请求enqueue。
- 而Call接口内部提供了Factory工厂方法模式(将对象的创建延迟到工厂类的子类去进行,从而实现动态配置)。
Call接口定义了请求执行的标准:
1public interface Call extends Cloneable { 2 Request request(); 3 Response execute() throws IOException; 4 void enqueue(Callback responseCallback); 5 void cancel(); 6 boolean isExecuted(); 7 boolean isCanceled(); 8 Timeout timeout(); 9 Call clone(); 10} 11
RealCall实现:
- 同步执行:
execute()方法直接在当前线程执行 - 异步执行:
enqueue()方法提交到线程池执行 - 请求取消:支持请求的取消操作
3.3.1 核心方法对比
| 特性 | execute() | enqueue() |
|---|---|---|
| 执行方式 | 同步阻塞 | 异步非阻塞 |
| 线程模型 | 当前线程执行 | 线程池执行 |
| 返回方式 | 直接返回Response | 通过Callback回调 |
| 异常处理 | 抛出IOException | 通过Callback.onFailure |
| 调度管理 | 简单记录 | 复杂的队列调度 |
3.3.2 执行流程架构图
1graph TB 2 A[应用调用] --> B{选择执行方式} 3 B -->|同步| C[call.execute] 4 B -->|异步| D[call.enqueue] 5 6 C --> E[Dispatcher.executed] 7 D --> F[Dispatcher.enqueue] 8 9 E --> G[getResponseWithInterceptorChain] 10 F --> H[AsyncCall入队] 11 H --> I[promoteAndExecute] 12 I --> J[线程池执行AsyncCall] 13 J --> K[AsyncCall.execute] 14 K --> G 15 16 G --> L[拦截器链处理] 17 L --> M[网络请求] 18 M --> N[Response返回] 19 20 N --> O{执行方式} 21 O -->|同步| P[直接返回Response] 22 O -->|异步| Q[Callback.onResponse] 23 24 style C fill:#e1f5fe 25 style D fill:#f3e5f5 26 style G fill:#fff3e0 27 style L fill:#e8f5e8 28
3.3.3 Execute执行时序图
1sequenceDiagram 2 participant App as 应用代码 3 participant RealCall as RealCall 4 participant Transmitter as Transmitter 5 participant Dispatcher as Dispatcher 6 participant Chain as InterceptorChain 7 participant Network as 网络层 8 9 App->>RealCall: execute() 10 11 Note over RealCall: 1. 检查执行状态 12 RealCall->>RealCall: synchronized检查executed 13 alt 已执行 14 RealCall-->>App: IllegalStateException 15 end 16 RealCall->>RealCall: executed = true 17 18 Note over RealCall: 2. 超时和生命周期管理 19 RealCall->>Transmitter: timeoutEnter() 20 RealCall->>Transmitter: callStart() 21 22 Note over RealCall: 3. 调度器管理 23 RealCall->>Dispatcher: executed(this) 24 Note over Dispatcher: 添加到runningSyncCalls队列 25 26 Note over RealCall: 4. 执行请求 27 RealCall->>Chain: getResponseWithInterceptorChain() 28 Chain->>Network: 网络请求处理 29 Network-->>Chain: Response 30 Chain-->>RealCall: Response 31 32 Note over RealCall: 5. 清理工作 33 RealCall->>Dispatcher: finished(this) 34 Note over Dispatcher: 从runningSyncCalls移除 35 36 RealCall-->>App: Response 37
3.3.4 Enqueue执行时序图
1sequenceDiagram 2 participant App as 应用代码 3 participant RealCall as RealCall 4 participant Dispatcher as Dispatcher 5 participant AsyncCall as AsyncCall 6 participant ThreadPool as 线程池 7 participant Chain as InterceptorChain 8 participant Callback as Callback 9 10 App->>RealCall: enqueue(callback) 11 12 Note over RealCall: 1. 状态检查和设置 13 RealCall->>RealCall: synchronized检查executed 14 RealCall->>RealCall: executed = true 15 16 Note over RealCall: 2. 创建AsyncCall 17 RealCall->>AsyncCall: new AsyncCall(callback) 18 RealCall->>Dispatcher: enqueue(asyncCall) 19 20 Note over Dispatcher: 3. 调度逻辑 21 Dispatcher->>Dispatcher: 添加到readyAsyncCalls 22 Dispatcher->>Dispatcher: promoteAndExecute() 23 24 alt 可以立即执行 25 Dispatcher->>Dispatcher: 移动到runningAsyncCalls 26 Dispatcher->>AsyncCall: executeOn(executorService) 27 AsyncCall->>ThreadPool: execute(this) 28 29 Note over ThreadPool: 4. 异步执行 30 ThreadPool->>AsyncCall: run() 31 AsyncCall->>AsyncCall: execute() 32 AsyncCall->>Chain: getResponseWithInterceptorChain() 33 Chain-->>AsyncCall: Response 34 35 Note over AsyncCall: 5. 回调处理 36 AsyncCall->>Callback: onResponse(call, response) 37 AsyncCall->>Dispatcher: finished(this) 38 else 需要等待 39 Note over Dispatcher: 保持在readyAsyncCalls队列中 40 end 41 42 RealCall-->>App: void (立即返回) 43
3.4 Dispatcher调度器
网络请求肯定涉及多线程,如何处理大量任务?采用Dispatcher作为调度,与线程池配合实现了高并发,低阻塞的的运行。针对请求任务,采用Deque作为集合,按照入队的顺序先进先出。
Dispatcher负责管理请求的执行调度:
1public final class Dispatcher { 2 private int maxRequests = 64; // 最大并发请求数 3 private int maxRequestsPerHost = 5; // 单主机最大并发数 4 5 // 等待执行的异步请求队列 6 private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>(); 7 // 正在执行的异步请求队列 8 private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>(); 9 // 正在执行的同步请求队列 10 private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>(); 11} 12
调度策略:
- 最大并发请求数限制(默认64个)
- 单主机最大并发数限制(默认5个)
- 使用双端队列管理等待和运行中的请求
- 自动的线程池管理
3.4.1 Dispatcher架构图
1graph TB 2 A[Dispatcher] --> B[ExecutorService] 3 A --> C[readyAsyncCalls] 4 A --> D[runningAsyncCalls] 5 A --> E[runningSyncCalls] 6 7 B --> F[ThreadPoolExecutor] 8 F --> G[核心线程数: 0] 9 F --> H[最大线程数: Integer.MAX_VALUE] 10 F --> I[空闲时间: 60秒] 11 F --> J[队列: SynchronousQueue] 12 13 C --> K[等待执行的异步请求] 14 D --> L[正在执行的异步请求] 15 E --> M[正在执行的同步请求] 16 17 style A fill:#e3f2fd 18 style B fill:#f3e5f5 19 style F fill:#e8f5e8 20
3.4.2 异步调度架构
1graph TB 2 subgraph "Dispatcher异步调度架构" 3 A[Dispatcher] --> B[ExecutorService] 4 A --> C[readyAsyncCalls] 5 A --> D[runningAsyncCalls] 6 A --> E[runningSyncCalls] 7 8 B --> F[ThreadPoolExecutor] 9 F --> G[核心线程池] 10 F --> H[最大线程数] 11 F --> I[队列管理] 12 13 subgraph "调度策略" 14 J[最大并发请求] 15 K[单主机最大请求] 16 L[空闲回调] 17 end 18 19 subgraph "请求队列" 20 C --> M[等待队列] 21 D --> N[执行队列] 22 E --> O[同步队列] 23 end 24 end 25
3.4.3 调度策略流程图
1flowchart TD 2 A[AsyncCall入队] --> B[添加到readyAsyncCalls] 3 B --> C[调用promoteAndExecute] 4 C --> D{检查执行条件} 5 6 D --> E{总请求数 < maxRequests?} 7 E -->|否| F[保持在ready队列] 8 E -->|是| G{主机请求数 < maxRequestsPerHost?} 9 10 G -->|否| H[继续检查下一个] 11 G -->|是| I[移动到running队列] 12 13 I --> J[callsPerHost计数+1] 14 J --> K[提交到线程池执行] 15 K --> L[AsyncCall.execute] 16 17 L --> M[执行网络请求] 18 M --> N[请求完成] 19 N --> O[调用finished方法] 20 O --> P[callsPerHost计数-1] 21 P --> Q[从running队列移除] 22 Q --> R[再次调用promoteAndExecute] 23 R --> S[尝试执行ready队列中的请求] 24 25 H --> T{还有更多请求?} 26 T -->|是| D 27 T -->|否| U[结束本轮调度] 28 29 F --> U 30 S --> U 31
3.5 拦截器机制
OKHttp有两种调用方式,一种是阻塞的同步请求,一种是异步的非阻塞的请求。
但是无论同步还是异步都会调用下RealCall的 getResponseWithInterceptorChain方法来完成请求,同时将返回数据或者状态通过Callback来完成。
设计拦截器的核心原理
Interceptor 负责拦截和分发。先来看看含义:观察,修改以及可能短路的请求输出和响应请求的回来。通常情况下拦截器用来添加,移除或者转换请求或者回应的头部信息。
拦截器,就像水管一样,把一节一节的水管(拦截器)连起来,形成一个回路。实际上client到server也是如此,通过一个又一个的interceptor串起来,然后把数据发送到服务器,又能接受返回的数据,每一个拦截器(水管)都有自己的作用,分别处理不同东西,比如消毒,净化,去杂质,就像一层层过滤网一样。
接口是如何设计的
1public interface Interceptor { 2 //负责拦截 3 Response intercept(Chain chain) throws IOException; 4 interface Chain { 5 //负责分发、前行 6 Response proceed(Request request) throws IOException; 7 } 8} 9
3.5.1 拦截器时序图
OkHttp的拦截器采用责任链模式,每个拦截器负责特定的功能:
1sequenceDiagram 2 participant App as 应用代码 3 participant Client as OkHttpClient 4 participant RealCall as RealCall 5 participant Chain as InterceptorChain 6 participant AppInt as 应用拦截器 7 participant RetryInt as 重试拦截器 8 participant BridgeInt as 桥接拦截器 9 participant CacheInt as 缓存拦截器 10 participant ConnInt as 连接拦截器 11 participant NetInt as 网络拦截器 12 participant CallInt as 调用服务器拦截器 13 14 App->>Client: newCall(request) 15 Client->>RealCall: create 16 App->>RealCall: execute() 17 RealCall->>Chain: proceed(request) 18 Chain->>AppInt: intercept(chain) 19 AppInt->>RetryInt: chain.proceed() 20 RetryInt->>BridgeInt: chain.proceed() 21 BridgeInt->>CacheInt: chain.proceed() 22 CacheInt->>ConnInt: chain.proceed() 23 ConnInt->>NetInt: chain.proceed() 24 NetInt->>CallInt: chain.proceed() 25 CallInt-->>NetInt: response 26 NetInt-->>ConnInt: response 27 ConnInt-->>CacheInt: response 28 CacheInt-->>BridgeInt: response 29 BridgeInt-->>RetryInt: response 30 RetryInt-->>AppInt: response 31 AppInt-->>Chain: response 32 Chain-->>RealCall: response 33 RealCall-->>App: response 34
3.5.2 拦截器类关系图
1classDiagram 2 class Interceptor { 3 <<interface>> 4 +intercept(Chain) Response 5 } 6 7 class Chain { 8 <<interface>> 9 +request() Request 10 +proceed(Request) Response 11 +connection() Connection 12 +call() Call 13 } 14 15 class RealInterceptorChain { 16 -List~Interceptor~ interceptors 17 -Transmitter transmitter 18 -Exchange exchange 19 -int index 20 -Request request 21 +proceed(Request) Response 22 +proceed(Request, Transmitter, Exchange) Response 23 } 24 25 class RetryAndFollowUpInterceptor { 26 -OkHttpClient client 27 -int MAX_FOLLOW_UPS 28 +intercept(Chain) Response 29 -recover(IOException, Transmitter, boolean, Request) boolean 30 -followUpRequest(Response, Route) Request 31 } 32 33 class BridgeInterceptor { 34 -CookieJar cookieJar 35 +intercept(Chain) Response 36 -cookieHeader(List~Cookie~) String 37 } 38 39 class CacheInterceptor { 40 -InternalCache cache 41 +intercept(Chain) Response 42 -cacheCandidate(Request) Response 43 -strategy(Request, Response) CacheStrategy 44 } 45 46 class ConnectInterceptor { 47 -OkHttpClient client 48 +intercept(Chain) Response 49 } 50 51 class CallServerInterceptor { 52 -boolean forWebSocket 53 +intercept(Chain) Response 54 } 55 56 Interceptor <|-- RetryAndFollowUpInterceptor 57 Interceptor <|-- BridgeInterceptor 58 Interceptor <|-- CacheInterceptor 59 Interceptor <|-- ConnectInterceptor 60 Interceptor <|-- CallServerInterceptor 61 Chain <|-- RealInterceptorChain 62 RealInterceptorChain --> Interceptor : uses 63
3.5.3 内置拦截器详解
- 应用拦截器(Application Interceptors)
- 用户自定义的拦截器
- 在请求发送前和响应接收后执行
- 可以修改请求和响应
- 重试和重定向拦截器(RetryAndFollowUpInterceptor)
- 处理请求失败重试
- 处理HTTP重定向
- 管理连接的获取和释放
- 桥接拦截器(BridgeInterceptor)
- 将用户请求转换为网络请求
- 添加必要的HTTP头(Content-Type、Content-Length等)
- 处理Cookie
- 处理GZIP压缩
- 缓存拦截器(CacheInterceptor)
- 实现HTTP缓存策略
- 处理缓存的读取和写入
- 支持强制缓存和协商缓存
- 连接拦截器(ConnectInterceptor)
- 建立与服务器的连接
- 管理连接池
- 处理HTTP/2连接复用
- 网络拦截器(Network Interceptors)
- 用户自定义的网络级拦截器
- 在实际网络请求前后执行
- 调用服务器拦截器(CallServerInterceptor)
- 实际的网络IO操作
- 发送请求数据
- 读取响应数据
3.5.4 重定向拦截器
核心功能
- 异常恢复:处理网络异常和连接失败
- 重定向处理:自动处理HTTP重定向响应
- 重试逻辑:根据策略决定是否重试请求
1flowchart TD 2 A[接收请求] --> B[准备连接] 3 B --> C{是否被取消?} 4 C -->|是| D[抛出IOException] 5 C -->|否| E[执行下一个拦截器] 6 7 E --> F{是否发生异常?} 8 F -->|是| G[调用recover方法] 9 F -->|否| H[检查响应状态] 10 11 G --> I{是否可恢复?} 12 I -->|是| J[继续重试] 13 I -->|否| K[抛出异常] 14 15 H --> L[调用followUpRequest] 16 L --> M{需要重定向?} 17 M -->|否| N[返回响应] 18 M -->|是| O{重定向次数超限?} 19 20 O -->|是| P[抛出ProtocolException] 21 O -->|否| Q[更新请求] 22 Q --> R[关闭当前响应] 23 R --> J 24 25 J --> B 26 27 style G fill:#ffebee 28 style I fill:#fff3e0 29 style M fill:#e8f5e8 30 style O fill:#fce4ec 31
3.5.6 缓存拦截器
核心功能
- 缓存策略:根据HTTP缓存规范决定缓存行为
- 缓存读取:从缓存中读取有效的响应
- 缓存写入:将可缓存的响应写入缓存
- 条件请求:发送If-None-Match、If-Modified-Since等条件请求
1flowchart TD 2 A[接收请求] --> B[从缓存获取候选响应] 3 B --> C[计算缓存策略] 4 C --> D{网络请求为null?} 5 6 D -->|是| E{缓存响应为null?} 7 D -->|否| F{缓存响应为null?} 8 9 E -->|是| G[返回504错误] 10 E -->|否| H[返回缓存响应] 11 12 F -->|是| I[执行网络请求] 13 F -->|否| J[执行条件网络请求] 14 15 I --> K[获取网络响应] 16 J --> L[获取网络响应] 17 18 K --> M{响应可缓存?} 19 L --> N{响应状态码?} 20 21 N -->|304| O[更新缓存响应] 22 N -->|其他| P[使用网络响应] 23 24 O --> Q[返回更新后的缓存响应] 25 P --> R{响应可缓存?} 26 27 M -->|是| S[写入缓存] 28 M -->|否| T[返回网络响应] 29 30 R -->|是| U[写入缓存] 31 R -->|否| V[返回网络响应] 32 33 S --> T 34 U --> V 35 36 style D fill:#e3f2fd 37 style E fill:#f3e5f5 38 style F fill:#e8f5e8 39 style M fill:#fff3e0 40 style N fill:#fce4ec 41 style R fill:#e0f2f1 42
3.5.7 网络请求拦截器
CallServerInterceptor(网络请求拦截器)
- 请求发送:将HTTP请求发送到服务器
- 响应接收:接收服务器的HTTP响应
- 流控制:管理请求和响应的数据流
- 协议处理:处理HTTP/1.1和HTTP/2的具体协议细节
1sequenceDiagram 2 participant Chain as RealInterceptorChain 3 participant CallServer as CallServerInterceptor 4 participant Exchange as Exchange 5 participant Codec as ExchangeCodec 6 participant Connection as RealConnection 7 participant Server as 服务器 8 9 Chain->>CallServer: intercept(chain) 10 CallServer->>Exchange: writeRequestHeaders(request) 11 Exchange->>Codec: writeRequestHeaders(request) 12 Codec->>Connection: 发送请求头 13 Connection->>Server: HTTP请求头 14 15 alt 有请求体 16 CallServer->>Exchange: createRequestBody(request) 17 CallServer->>CallServer: 写入请求体数据 18 CallServer->>Exchange: finishRequest() 19 Exchange->>Codec: finishRequest() 20 Codec->>Connection: 发送请求体 21 Connection->>Server: HTTP请求体 22 end 23 24 CallServer->>Exchange: readResponseHeaders() 25 Exchange->>Codec: readResponseHeaders() 26 Codec->>Connection: 读取响应头 27 Connection->>Server: 请求响应头 28 Server-->>Connection: HTTP响应头 29 Connection-->>Codec: 响应头数据 30 Codec-->>Exchange: 解析后的响应头 31 Exchange-->>CallServer: Response.Builder 32 33 alt 有响应体 34 CallServer->>Exchange: openResponseBody(response) 35 Exchange->>Codec: openResponseBodySource(response) 36 Note over CallServer: 创建响应体Source 37 end 38 39 CallServer-->>Chain: 完整的Response对象 40
3.5.8 拦截器链状态管理
1stateDiagram-v2 2 [*] --> Created: new RealInterceptorChain() 3 Created --> Executing: proceed()调用 4 Executing --> NextInterceptor: index++, 创建新链 5 NextInterceptor --> Executing: interceptor.intercept() 6 Executing --> Completed: 返回Response 7 Executing --> Error: 异常发生 8 Error --> [*] 9 Completed --> [*] 10 11 note right of NextInterceptor 12 每次proceed()调用都会: 13 1. index + 1 14 2. 创建新的RealInterceptorChain 15 3. 传递给下一个拦截器 16 end note 17
3.6 Response返回
Response核心职责
- 响应封装:统一封装HTTP响应的所有信息
- 流式处理:支持大文件的流式读取和处理
- 内存管理:优化内存使用,避免大响应体的内存溢出
- 协议适配:支持HTTP/1.1和HTTP/2协议的响应处理
- 缓存集成:与缓存系统无缝集成
3.6.1 类层次结构图
1classDiagram 2 class Response { 3 -Request request 4 -Protocol protocol 5 -int code 6 -String message 7 -Headers headers 8 -ResponseBody body 9 -Response networkResponse 10 -Response cacheResponse 11 -Response priorResponse 12 -Handshake handshake 13 -long sentRequestAtMillis 14 -long receivedResponseAtMillis 15 +Builder newBuilder() 16 +boolean isSuccessful() 17 +boolean isRedirect() 18 +String header(String) 19 +List~String~ headers(String) 20 +ResponseBody body() 21 +void close() 22 } 23 24 class ResponseBody { 25 <<abstract>> 26 +MediaType contentType() 27 +long contentLength() 28 +BufferedSource source() 29 +String string() 30 +byte[] bytes() 31 +InputStream byteStream() 32 +Reader charStream() 33 +void close() 34 } 35 36 class RealResponseBody { 37 -String contentTypeString 38 -long contentLength 39 -BufferedSource source 40 +MediaType contentType() 41 +long contentLength() 42 +BufferedSource source() 43 } 44 45 class Headers { 46 -String[] namesAndValues 47 +String get(String) 48 +List~String~ values(String) 49 +Set~String~ names() 50 +int size() 51 +String name(int) 52 +String value(int) 53 +Builder newBuilder() 54 } 55 56 class Builder { 57 -Request request 58 -Protocol protocol 59 -int code 60 -String message 61 -Headers.Builder headers 62 -ResponseBody body 63 +Builder request(Request) 64 +Builder protocol(Protocol) 65 +Builder code(int) 66 +Builder message(String) 67 +Builder header(String, String) 68 +Builder headers(Headers) 69 +Builder body(ResponseBody) 70 +Response build() 71 } 72 73 Response --> ResponseBody : contains 74 Response --> Headers : contains 75 Response --> Builder : creates 76 ResponseBody <|-- RealResponseBody : implements 77 Response -- Builder : inner class 78
3.6.2 创建流程架构图
Response创建流程架构图
1graph TB 2 A[服务器响应] --> B[ExchangeCodec读取] 3 B --> C{协议类型} 4 5 C -->|HTTP/1.1| D[Http1ExchangeCodec] 6 C -->|HTTP/2| E[Http2ExchangeCodec] 7 8 D --> F[解析状态行] 9 E --> G[解析HTTP/2帧] 10 11 F --> H[解析响应头] 12 G --> H 13 14 H --> I[创建Response.Builder] 15 I --> J[设置基本信息] 16 J --> K[设置响应头] 17 K --> L[创建ResponseBody] 18 L --> M[构建Response对象] 19 20 M --> N[拦截器处理] 21 N --> O[返回给应用层] 22 23 style D fill:#e3f2fd 24 style E fill:#f3e5f5 25 style I fill:#e8f5e8 26 style L fill:#fff3e0 27 style N fill:#fce4ec 28
3.6.3 状态行解析流程图
1flowchart TD 2 A[读取状态行] --> B[StatusLine.parse] 3 B --> C{解析成功?} 4 C -->|否| D[抛出ProtocolException] 5 C -->|是| E[提取协议版本] 6 E --> F[提取状态码] 7 F --> G[提取状态消息] 8 G --> H[创建Response.Builder] 9 H --> I[设置protocol] 10 I --> J[设置code] 11 J --> K[设置message] 12 K --> L{状态码检查} 13 L -->|100 Continue| M{期望Continue?} 14 L -->|其他| N[读取响应头] 15 M -->|是| O[返回null] 16 M -->|否| P[返回Builder] 17 N --> Q[返回完整Builder] 18 19 style C fill:#fff3e0 20 style L fill:#e3f2fd 21 style M fill:#f3e5f5 22
3.6.4 Headers解析流程
1sequenceDiagram 2 participant Codec as ExchangeCodec 3 participant Reader as Source/BufferedSource 4 participant Headers as Headers.Builder 5 participant Parser as HeaderParser 6 7 Codec->>Reader: readHeaderLine() 8 loop 读取每一行 9 Reader-->>Codec: 响应头行 10 alt 空行(响应头结束) 11 Codec->>Codec: break 12 else 正常响应头 13 Codec->>Parser: 解析头部名称和值 14 Parser-->>Codec: name, value 15 Codec->>Headers: addLenient(name, value) 16 else 多行头部(折叠) 17 Codec->>Parser: 处理折叠行 18 Parser-->>Codec: 合并后的值 19 Codec->>Headers: 更新头部值 20 end 21 end 22 Headers-->>Codec: Headers对象 23
3.6.5 ResponseBody架构设计
1classDiagram 2 class ResponseBody { 3 <<abstract>> 4 +MediaType contentType() 5 +long contentLength() 6 +BufferedSource source() 7 +String string() 8 +byte[] bytes() 9 +InputStream byteStream() 10 +Reader charStream() 11 +void close() 12 +create(MediaType, String)$ ResponseBody 13 +create(MediaType, byte[])$ ResponseBody 14 +create(MediaType, long, BufferedSource)$ ResponseBody 15 } 16 17 class RealResponseBody { 18 -String contentTypeString 19 -long contentLength 20 -BufferedSource source 21 +MediaType contentType() 22 +long contentLength() 23 +BufferedSource source() 24 } 25 26 class CacheWritingResponseBody { 27 -ResponseBody delegate 28 -CacheRequest cacheRequest 29 -BufferedSink cacheBody 30 -Source cacheWritingSource 31 +long contentLength() 32 +BufferedSource source() 33 } 34 35 class GzipResponseBody { 36 -ResponseBody responseBody 37 -GzipSource gzipSource 38 +long contentLength() 39 +BufferedSource source() 40 } 41 42 ResponseBody <|-- RealResponseBody 43 ResponseBody <|-- CacheWritingResponseBody 44 ResponseBody <|-- GzipResponseBody 45 CacheWritingResponseBody --> ResponseBody : delegates to 46 GzipResponseBody --> ResponseBody : wraps 47
3.6.6 ResponseBody数据读取
1graph TB 2 A[ResponseBody数据读取] --> B{读取方式选择} 3 4 B -->|小数据| C[string方法] 5 B -->|二进制数据| D[bytes方法] 6 B -->|流式读取| E[source方法] 7 B -->|InputStream| F[byteStream方法] 8 B -->|字符流| G[charStream方法] 9 10 C --> H[一次性读取到内存] 11 D --> I[一次性读取到字节数组] 12 E --> J[BufferedSource流式读取] 13 F --> K[InputStream包装] 14 G --> L[Reader字符流] 15 16 H --> M{数据大小} 17 I --> M 18 M -->|小于1MB| N[适合] 19 M -->|大于1MB| O[可能OOM] 20 21 J --> P[内存友好] 22 K --> P 23 L --> P 24 25 style C fill:#ffebee 26 style D fill:#ffebee 27 style E fill:#e8f5e8 28 style F fill:#e8f5e8 29 style G fill:#e8f5e8 30 style O fill:#ffcdd2 31 style P fill:#c8e6c9 32
3.6.7 Response生命周期
1sequenceDiagram 2 participant App as 应用代码 3 participant Call as RealCall 4 participant Chain as InterceptorChain 5 participant Exchange as Exchange 6 participant Codec as ExchangeCodec 7 participant Response as Response 8 participant Body as ResponseBody 9 10 App->>Call: execute() / enqueue() 11 Call->>Chain: getResponseWithInterceptorChain() 12 Chain->>Exchange: 拦截器链处理 13 Exchange->>Codec: readResponseHeaders() 14 Codec-->>Exchange: Response.Builder 15 Exchange->>Exchange: openResponseBody() 16 Exchange->>Body: 创建ResponseBody 17 Body-->>Exchange: ResponseBody实例 18 Exchange->>Response: Builder.body().build() 19 Response-->>Chain: 完整Response 20 Chain-->>Call: Response 21 Call-->>App: Response 22 23 Note over App: 应用处理Response 24 App->>Body: string() / bytes() / source() 25 Body-->>App: 响应数据 26 App->>Response: close() 27 Response->>Body: close() 28 Body->>Codec: 关闭底层连接 29
3.6.8 响应数据处理
1graph TB 2 A[响应数据处理] --> B{数据大小评估} 3 B -->|小于64KB| C[直接内存读取] 4 B -->|64KB-1MB| D[分块读取] 5 B -->|大于1MB| E[流式处理] 6 7 C --> F[string/bytes方法] 8 D --> G[BufferedSource分块] 9 E --> H[InputStream/Reader] 10 11 F --> I[一次性分配内存] 12 G --> J[固定大小缓冲区] 13 H --> K[按需分配] 14 15 I --> L{内存充足?} 16 L -->|是| M[正常处理] 17 L -->|否| N[OutOfMemoryError] 18 19 J --> O[内存可控] 20 K --> O 21 22 style N fill:#ffcdd2 23 style O fill:#c8e6c9 24 style M fill:#e8f5e8 25
3.6.9 Response错误处理
1flowchart TD 2 A[Response处理] --> B{状态码检查} 3 B -->|2xx| C[成功响应] 4 B -->|3xx| D[重定向处理] 5 B -->|4xx| E[客户端错误] 6 B -->|5xx| F[服务器错误] 7 8 C --> G[正常处理ResponseBody] 9 D --> H[RetryAndFollowUpInterceptor处理] 10 E --> I[应用层错误处理] 11 F --> J[可能重试] 12 13 G --> K{ResponseBody读取} 14 K -->|成功| L[返回数据] 15 K -->|IO异常| M[连接错误处理] 16 K -->|协议异常| N[协议错误处理] 17 18 H --> O[自动重定向] 19 I --> P[返回错误Response] 20 J --> Q[重试或失败] 21 22 M --> R[关闭连接] 23 N --> R 24 R --> S[抛出异常] 25 26 style E fill:#fff3e0 27 style F fill:#ffebee 28 style M fill:#ffcdd2 29 style N fill:#ffcdd2 30
3.6.10 Response缓存机制
1sequenceDiagram 2 participant App as 应用 3 participant Cache as CacheInterceptor 4 participant DiskCache as DiskLruCache 5 participant Network as 网络层 6 participant Response as Response 7 8 App->>Cache: 请求 9 Cache->>DiskCache: 查找缓存 10 alt 缓存命中且有效 11 DiskCache-->>Cache: 缓存Response 12 Cache->>Response: 创建缓存Response 13 Response-->>App: 返回缓存数据 14 else 缓存过期或不存在 15 Cache->>Network: 网络请求 16 Network-->>Cache: 网络Response 17 Cache->>DiskCache: 存储Response 18 Cache->>Response: 包装为缓存写入Response 19 Response-->>App: 返回网络数据 20 Note over Response: 读取时同时写入缓存 21 end 22
04.核心流程分析
4.1 请求执行流程
1flowchart TD 2 A[创建OkHttpClient] --> B[构建Request] 3 B --> C[调用newCall创建Call] 4 C --> D{同步还是异步?} 5 6 D -->|同步| E[call.execute] 7 D -->|异步| F[call.enqueue] 8 9 E --> G[Dispatcher调度] 10 F --> H[加入异步队列] 11 H --> I[线程池执行] 12 I --> G 13 14 G --> J[构建拦截器链] 15 J --> K[依次执行拦截器] 16 K --> L[发送网络请求] 17 L --> M[接收响应] 18 M --> N[拦截器链处理响应] 19 N --> O[返回Response] 20 21 O --> P{异步?} 22 P -->|是| Q[回调Callback] 23 P -->|否| R[直接返回] 24
4.2 连接管理流程
1sequenceDiagram 2 participant Call as RealCall 3 participant ConnInt as ConnectInterceptor 4 participant Pool as ConnectionPool 5 participant Conn as RealConnection 6 participant Socket as Socket 7 8 Call->>ConnInt: intercept() 9 ConnInt->>Pool: get(address) 10 11 alt 连接池中有可用连接 12 Pool-->>ConnInt: 返回现有连接 13 else 需要创建新连接 14 ConnInt->>Conn: create new 15 Conn->>Socket: connect() 16 Socket-->>Conn: connected 17 Conn-->>Pool: put(connection) 18 Pool-->>ConnInt: 返回新连接 19 end 20 21 ConnInt->>Call: proceed with connection 22
4.3 缓存处理流程
1flowchart TD 2 A[请求到达缓存拦截器] --> B{缓存是否存在?} 3 4 B -->|否| C[继续网络请求] 5 B -->|是| D{缓存是否有效?} 6 7 D -->|有效| E[返回缓存响应] 8 D -->|需要验证| F[添加条件请求头] 9 D -->|过期| C 10 11 F --> G[发送条件请求] 12 G --> H{服务器响应} 13 14 H -->|304 Not Modified| I[返回缓存内容] 15 H -->|200 OK| J[更新缓存并返回新内容] 16 17 C --> K[网络请求] 18 K --> L{响应可缓存?} 19 L -->|是| M[存储到缓存] 20 L -->|否| N[直接返回响应] 21 M --> N 22
05.关键技术特性
5.1 连接池管理
OkHttp使用连接池来复用HTTP连接,提高性能:
1public final class ConnectionPool { 2 private static final Executor executor = new ThreadPoolExecutor( 3 0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, 4 new SynchronousQueue<>(), 5 Util.threadFactory("OkHttp ConnectionPool", true) 6 ); 7 8 private final RealConnectionPool delegate; 9 10 public ConnectionPool() { 11 this(5, 5, TimeUnit.MINUTES); 12 } 13 14 public ConnectionPool(int maxIdleConnections, long keepAliveDuration, TimeUnit timeUnit) { 15 this.delegate = new RealConnectionPool(taskRunner, maxIdleConnections, keepAliveDuration, timeUnit); 16 } 17} 18
连接池特性:
- 默认最大空闲连接数:5个
- 默认连接保活时间:5分钟
- 自动清理过期连接
- 支持HTTP/1.1和HTTP/2连接复用
1flowchart TD 2 A[ConnectionPool创建] --> B[设置最大空闲连接数: 5] 3 B --> C[设置连接保活时间: 5分钟] 4 C --> D[创建RealConnectionPool] 5 D --> E[启动清理线程池] 6 7 E --> F[连接使用流程] 8 F --> G{需要新连接?} 9 G -->|是| H[创建新连接] 10 G -->|否| I[复用现有连接] 11 12 H --> J[连接加入池中] 13 I --> K[更新连接使用时间] 14 J --> L[连接使用完毕] 15 K --> L 16 17 L --> M[连接变为空闲状态] 18 M --> N[清理线程检查] 19 N --> O{连接过期?} 20 O -->|是| P[移除并关闭连接] 21 O -->|否| Q[保持连接] 22 23 P --> R[连接池维护完成] 24 Q --> R 25 26 style A fill:#e3f2fd 27 style D fill:#f3e5f5 28 style G fill:#fff3e0 29 style O fill:#ffebee 30
5.2 HTTP/2支持
OkHttp完整支持HTTP/2协议:
- 多路复用:单个连接上并发处理多个请求
- 服务器推送:服务器主动推送资源
- 头部压缩:HPACK算法压缩HTTP头部
- 流量控制:精确控制数据传输速率
5.2.1 HTTP/2连接架构
1graph TB 2 subgraph "HTTP/2多路复用架构" 3 A[Http2Connection] --> B[Http2Writer] 4 A --> C[Http2Reader] 5 A --> D[Settings] 6 A --> E[流管理器] 7 8 E --> F[Http2Stream 1] 9 E --> G[Http2Stream 2] 10 E --> H[Http2Stream N] 11 12 subgraph "流控制" 13 I[连接级流控] 14 J[流级流控] 15 K[窗口更新] 16 end 17 18 subgraph "帧处理" 19 L[DATA帧] 20 M[HEADERS帧] 21 N[SETTINGS帧] 22 O[WINDOW_UPDATE帧] 23 P[PING帧] 24 end 25 26 F --> I 27 G --> I 28 H --> I 29 30 F --> J 31 G --> J 32 H --> J 33 end 34
5.3 缓存机制设计
实现完整的HTTP缓存策略:
1public final class CacheInterceptor implements Interceptor { 2 @Override 3 public Response intercept(Chain chain) throws IOException { 4 Response cacheCandidate = cache != null ? cache.get(chain.request()) : null; 5 6 long now = System.currentTimeMillis(); 7 CacheStrategy strategy = new CacheStrategy.Factory(now, chain.request(), cacheCandidate).get(); 8 Request networkRequest = strategy.networkRequest; 9 Response cacheResponse = strategy.cacheResponse; 10 11 // 缓存策略处理逻辑 12 if (networkRequest == null && cacheResponse == null) { 13 return new Response.Builder() 14 .request(chain.request()) 15 .protocol(Protocol.HTTP_1_1) 16 .code(504) 17 .message("Unsatisfiable Request (only-if-cached)") 18 .build(); 19 } 20 21 if (networkRequest == null) { 22 return cacheResponse.newBuilder() 23 .cacheResponse(stripBody(cacheResponse)) 24 .build(); 25 } 26 27 // 继续网络请求... 28 } 29} 30
5.3.1 缓存架构设计
1graph TB 2 subgraph "OkHttp缓存架构" 3 A[OkHttpClient] --> B[CacheInterceptor] 4 B --> C[CacheStrategy] 5 C --> D[Cache] 6 D --> E[DiskLruCache] 7 8 F[Request] --> G[CacheControl] 9 H[Response] --> I[Headers] 10 I --> J[CacheControl] 11 12 B --> K[InternalCache] 13 K --> L[CacheRequest] 14 K --> M[Response缓存] 15 16 subgraph "缓存决策" 17 C --> N[网络请求] 18 C --> O[缓存响应] 19 C --> P[条件请求] 20 end 21 22 subgraph "存储层" 23 E --> Q[Journal文件] 24 E --> R[Entry文件] 25 E --> S[Snapshot] 26 end 27 end 28
5.3.2 缓存核心组件
1classDiagram 2 class Cache { 3 -DiskLruCache cache 4 -InternalCache internalCache 5 +get(Request) Response 6 +put(Response) CacheRequest 7 +remove(Request) 8 +urls() Iterator 9 +size() long 10 +maxSize() long 11 } 12 13 class CacheInterceptor { 14 -InternalCache cache 15 +intercept(Chain) Response 16 -cacheWritingResponse(CacheRequest, Response) Response 17 } 18 19 class CacheStrategy { 20 +Factory factory 21 +networkRequest Request 22 +cacheResponse Response 23 +get() CacheStrategy 24 } 25 26 class DiskLruCache { 27 -File directory 28 -long maxSize 29 -Map<String, Entry> lruEntries 30 +get(String) Snapshot 31 +edit(String) Editor 32 +remove(String) boolean 33 } 34 35 class CacheControl { 36 -boolean noCache 37 -boolean noStore 38 -int maxAgeSeconds 39 -int maxStaleSeconds 40 -int minFreshSeconds 41 +parse(Headers) CacheControl 42 } 43 44 Cache --> DiskLruCache 45 Cache --> InternalCache 46 CacheInterceptor --> Cache 47 CacheInterceptor --> CacheStrategy 48 CacheStrategy --> CacheControl 49
5.3.3 缓存决策流程
1flowchart TD 2 A[接收请求] --> B{检查缓存} 3 B -->|无缓存| C[发起网络请求] 4 B -->|有缓存| D{缓存是否新鲜} 5 6 D -->|新鲜| E[返回缓存响应] 7 D -->|过期| F{是否允许过期缓存} 8 9 F -->|允许| G{检查max-stale} 10 F -->|不允许| H{支持条件请求} 11 12 G -->|在允许范围内| E 13 G -->|超出范围| H 14 15 H -->|支持| I[发起条件请求] 16 H -->|不支持| C 17 18 I --> J{服务器响应} 19 J -->|304 Not Modified| K[更新缓存元数据] 20 J -->|200 OK| L[更新缓存内容] 21 22 K --> E 23 L --> M[返回新响应] 24 C --> N{响应可缓存} 25 N -->|可缓存| O[存储到缓存] 26 N -->|不可缓存| M 27 O --> M 28
5.3.4 磁盘缓存设计
DiskLruCache是OkHttp缓存的核心存储引擎,采用LRU(Least Recently Used)算法:
1graph TB 2 subgraph "DiskLruCache架构" 3 A[DiskLruCache] --> B[Journal文件] 4 A --> C[Entry映射] 5 A --> D[Executor线程池] 6 7 B --> E[操作日志] 8 E --> F[CLEAN记录] 9 E --> G[DIRTY记录] 10 E --> H[REMOVE记录] 11 E --> I[READ记录] 12 13 C --> J[Entry对象] 14 J --> K[文件索引] 15 J --> L[长度信息] 16 J --> M[访问时间] 17 18 subgraph "文件存储" 19 N[缓存目录] 20 N --> O[journal文件] 21 N --> P[journal.tmp] 22 N --> Q[journal.bkp] 23 N --> R[entry.0文件] 24 N --> S[entry.1文件] 25 end 26 end 27
5.3.5 缓存拦截器思想
CacheInterceptor核心流程
1sequenceDiagram 2 participant I as CacheInterceptor 3 participant C as Cache 4 participant D as DiskLruCache 5 participant F as FileSystem 6 7 I->>C: put(response) 8 C->>C: 计算缓存键 9 C->>D: edit(key) 10 D->>D: 创建Editor 11 D->>F: 创建临时文件 12 F-->>D: 文件句柄 13 D-->>C: Editor对象 14 C->>C: 创建CacheRequest 15 C-->>I: CacheRequest 16 17 Note over I: 写入响应数据 18 I->>I: cacheWritingResponse() 19 I->>I: 包装ResponseBody 20 21 Note over I: 数据流写入 22 loop 读取网络响应 23 I->>I: 读取数据块 24 I->>C: 写入缓存 25 I->>I: 写入客户端 26 end 27 28 I->>C: 完成写入 29 C->>D: editor.commit() 30 D->>F: 重命名临时文件 31 D->>D: 更新Journal 32 D-->>C: 成功 33 C-->>I: 完成 34
5.4 安全特性设计
在安全性方面采用了多层防护策略,涵盖传输层安全(TLS)、证书验证、主机名校验、数据完整性保护等多个维度。
- TLS支持:支持TLS 1.2和1.3
- 证书锁定:Certificate Pinning防止中间人攻击
- 主机名验证:严格的主机名验证
- 协议降级保护:防止协议降级攻击
5.4.1 安全组件架构图
1graph TB 2 A[OkHttpClient] --> B[SSL/TLS配置] 3 A --> C[证书验证] 4 A --> D[主机名校验] 5 A --> E[连接安全] 6 7 B --> F[SSLSocketFactory] 8 B --> G[X509TrustManager] 9 B --> H[ConnectionSpec] 10 B --> I[TlsVersion] 11 B --> J[CipherSuite] 12 13 C --> K[CertificatePinner] 14 C --> L[CertificateChainCleaner] 15 C --> M[TrustRootIndex] 16 17 D --> N[OkHostnameVerifier] 18 D --> O[HostnameVerifier] 19 20 E --> P[RealConnection] 21 E --> Q[Handshake] 22 E --> R[Protocol协商] 23 24 F --> S[平台SSL实现] 25 G --> T[证书信任链] 26 K --> U[证书固定] 27 L --> V[证书链清理] 28 N --> W[主机名匹配] 29 P --> X[TLS握手] 30 31 style A fill:#e3f2fd 32 style B fill:#f3e5f5 33 style C fill:#e8f5e8 34 style D fill:#fff3e0 35 style E fill:#fce4ec 36
5.4.2 安全数据流图
1sequenceDiagram 2 participant App as 应用程序 3 participant Client as OkHttpClient 4 participant Conn as RealConnection 5 participant SSL as SSLSocket 6 participant Server as 服务器 7 8 App->>Client: 创建HTTPS请求 9 Client->>Conn: 建立连接 10 Conn->>SSL: 创建SSL连接 11 12 Note over SSL,Server: TLS握手过程 13 SSL->>Server: ClientHello 14 Server->>SSL: ServerHello + Certificate 15 16 SSL->>SSL: 证书链验证 17 SSL->>SSL: 主机名验证 18 SSL->>SSL: 证书固定检查 19 20 alt 验证成功 21 SSL->>Server: ClientKeyExchange 22 Server->>SSL: Finished 23 SSL->>Conn: 安全连接建立 24 Conn->>Client: 连接就绪 25 Client->>App: 可以发送请求 26 else 验证失败 27 SSL->>Conn: 验证失败 28 Conn->>Client: 连接异常 29 Client->>App: 抛出安全异常 30 end 31
5.4.3 证书验证机制
OkHttp使用CertificateChainCleaner来清理和验证证书链:
1public abstract class CertificateChainCleaner { 2 public abstract List<Certificate> clean(List<Certificate> chain, String hostname) 3 throws SSLPeerUnverifiedException; 4 5 public static CertificateChainCleaner get(X509TrustManager trustManager) { 6 return Platform.get().buildCertificateChainCleaner(trustManager); 7 } 8 9 public static CertificateChainCleaner get(X509TrustManager trustManager, TrustRootIndex trustRootIndex) { 10 return new BasicCertificateChainCleaner(trustRootIndex); 11 } 12} 13
证书链验证流程
1sequenceDiagram 2 participant Client as OkHttpClient 3 participant Cleaner as CertificateChainCleaner 4 participant Trust as TrustManager 5 participant Root as TrustRootIndex 6 7 Client->>Cleaner: clean(certificateChain, hostname) 8 Cleaner->>Cleaner: 构建完整证书链 9 10 loop 对每个证书 11 Cleaner->>Root: findByIssuerAndSignature(cert) 12 Root-->>Cleaner: 返回匹配的根证书 13 end 14 15 Cleaner->>Trust: checkServerTrusted(chain, authType) 16 17 alt 验证成功 18 Trust-->>Cleaner: 验证通过 19 Cleaner-->>Client: 返回清理后的证书链 20 else 验证失败 21 Trust-->>Cleaner: 抛出异常 22 Cleaner-->>Client: 证书验证失败 23 end 24
5.4.4 主机名验证
OkHostnameVerifier实现,OkHttp实现了符合RFC 2818标准的主机名验证器
1flowchart TD 2 A[开始主机名验证] --> B{输入是IP地址?} 3 B -->|是| C[IP地址验证] 4 B -->|否| D[域名验证] 5 6 C --> E[获取证书SAN中的IP地址] 7 E --> F{IP地址匹配?} 8 F -->|是| G[验证成功] 9 F -->|否| H[验证失败] 10 11 D --> I[获取证书SAN中的DNS名称] 12 I --> J[遍历每个DNS名称] 13 J --> K{是通配符模式?} 14 15 K -->|否| L[精确匹配] 16 K -->|是| M[通配符验证] 17 18 L --> N{完全匹配?} 19 N -->|是| G 20 N -->|否| O{还有更多DNS名称?} 21 22 M --> P[检查通配符规则] 23 P --> Q{通配符匹配?} 24 Q -->|是| G 25 Q -->|否| O 26 27 O -->|是| J 28 O -->|否| H 29 30 style G fill:#c8e6c9 31 style H fill:#ffcdd2 32
5.4.5 中间人攻击防护
OkHttp通过多层防护机制防止中间人攻击:
1graph TB 2 A[中间人攻击防护] --> B[证书验证] 3 A --> C[证书固定] 4 A --> D[主机名验证] 5 A --> E[HSTS支持] 6 A --> F[证书透明度] 7 8 B --> G[证书链完整性检查] 9 B --> H[证书有效期验证] 10 B --> I[证书撤销检查] 11 12 C --> J[公钥固定] 13 C --> K[证书指纹固定] 14 C --> L[CA固定] 15 16 D --> M[SAN验证] 17 D --> N[通配符规则检查] 18 D --> O[IP地址验证] 19 20 E --> P[强制HTTPS重定向] 21 E --> Q[HSTS预加载] 22 23 F --> R[SCT验证] 24 F --> S[CT日志检查] 25 26 style A fill:#e3f2fd 27 style B fill:#f3e5f5 28 style C fill:#e8f5e8 29 style D fill:#fff3e0 30 style E fill:#fce4ec 31 style F fill:#e0f2f1 32
5.5 SSL/TLS流程
SSL配置层次图
1graph TB 2 A[SSL/TLS配置] --> B[SocketFactory] 3 A --> C[SSLSocketFactory] 4 A --> D[X509TrustManager] 5 A --> E[HostnameVerifier] 6 A --> F[CertificatePinner] 7 A --> G[ConnectionSpec] 8 9 B --> H[普通Socket创建] 10 C --> I[SSL Socket创建] 11 D --> J[证书信任验证] 12 E --> K[主机名验证] 13 F --> L[证书固定验证] 14 G --> M[连接规范配置] 15 16 I --> N[TLS握手] 17 J --> N 18 K --> N 19 L --> N 20 M --> N 21 22 N --> O[安全连接建立] 23 24 style A fill:#e3f2fd 25 style N fill:#f3e5f5 26 style O fill:#c8e6c9 27
5.5.1 TLS版本支持
OkHttp支持多个TLS版本,并提供了灵活的配置机制:
1public enum TlsVersion { 2 TLS_1_3("TLSv1.3"), // jdk11+, android10+ 3 TLS_1_2("TLSv1.2"), // jdk7+, android16+ 4 TLS_1_1("TLSv1.1"), // jdk7+, android16+ 5 TLS_1_0("TLSv1.0"), // jdk7+, android16+ 6 SSL_3_0("SSLv3"); // jdk6+, android9+ 7 8 public static final TlsVersion[] DEFAULT = { 9 TLS_1_3, TLS_1_2, TLS_1_1, TLS_1_0 10 }; 11} 12
5.5.2 TLS版本策略
1flowchart TD 2 A[开始TLS协商] --> B{服务器支持TLS 1.3?} 3 B -->|是| C[使用TLS 1.3] 4 B -->|否| D{服务器支持TLS 1.2?} 5 D -->|是| E[使用TLS 1.2] 6 D -->|否| F{服务器支持TLS 1.1?} 7 F -->|是| G[使用TLS 1.1] 8 F -->|否| H{服务器支持TLS 1.0?} 9 H -->|是| I[使用TLS 1.0] 10 H -->|否| J[连接失败] 11 12 C --> K[建立安全连接] 13 E --> K 14 G --> K 15 I --> K 16 17 style C fill:#c8e6c9 18 style E fill:#dcedc8 19 style G fill:#f0f4c3 20 style I fill:#fff9c4 21 style J fill:#ffcdd2 22
5.5.3 TLS握手过程
RealConnection负责建立安全的TLS连接:
1sequenceDiagram 2 participant Client as OkHttpClient 3 participant Conn as RealConnection 4 participant SSL as SSLSocket 5 participant Server as 服务器 6 participant Verifier as HostnameVerifier 7 participant Pinner as CertificatePinner 8 9 Client->>Conn: connectTls() 10 Conn->>SSL: createSocket() 11 Conn->>SSL: 配置连接规范 12 Conn->>SSL: startHandshake() 13 14 Note over SSL,Server: TLS握手协商 15 SSL->>Server: ClientHello 16 Server->>SSL: ServerHello + Certificate + ServerHelloDone 17 SSL->>Server: ClientKeyExchange + ChangeCipherSpec + Finished 18 Server->>SSL: ChangeCipherSpec + Finished 19 20 SSL->>Conn: 握手完成 21 Conn->>Conn: 获取握手信息 22 23 Conn->>Verifier: verify(hostname, session) 24 alt 主机名验证成功 25 Verifier-->>Conn: true 26 Conn->>Pinner: check(hostname, certificates) 27 alt 证书固定验证成功 28 Pinner-->>Conn: 验证通过 29 Conn->>Conn: 选择应用层协议 30 Conn-->>Client: 安全连接建立成功 31 else 证书固定验证失败 32 Pinner-->>Conn: SSLPeerUnverifiedException 33 Conn-->>Client: 连接失败 34 end 35 else 主机名验证失败 36 Verifier-->>Conn: false 37 Conn-->>Client: SSLPeerUnverifiedException 38 end 39
06.性能优化策略
6.1 连接复用
1graph LR 2 A[请求1] --> B[连接池] 3 C[请求2] --> B 4 D[请求3] --> B 5 B --> E[复用连接1] 6 B --> F[复用连接2] 7 E --> G[服务器] 8 F --> G 9
6.1.1 连接复用架构
1graph TB 2 subgraph "OkHttp连接复用架构" 3 A[OkHttpClient] --> B[ConnectionPool] 4 B --> C[RealConnectionPool] 5 C --> D[RealConnection] 6 7 E[Request] --> F[RealCall] 8 F --> G[ExchangeFinder] 9 G --> H[RouteSelector] 10 11 G --> I[Exchange] 12 I --> D 13 14 subgraph "连接管理" 15 C --> J[连接清理任务] 16 C --> K[连接复用逻辑] 17 C --> L[连接池统计] 18 end 19 20 subgraph "路由选择" 21 H --> M[Route] 22 H --> N[Proxy] 23 H --> O[InetSocketAddress] 24 end 25 26 subgraph "协议支持" 27 D --> P[HTTP/1.1] 28 D --> Q[HTTP/2] 29 D --> R[HTTPS/TLS] 30 end 31 end 32
6.2 请求合并
对于相同的请求,OkHttp会自动合并,避免重复请求。
6.3 压缩传输
- 自动GZIP压缩响应体
- 支持Brotli压缩算法
- 透明的压缩/解压缩处理
6.4 内存管理
- 使用Okio进行高效的IO操作
- 智能的缓冲区管理
- 及时释放不需要的资源
6.4.1 内存管理架构
1graph TB 2 subgraph "OkHttp内存管理架构" 3 A[内存管理] --> B[对象池化] 4 A --> C[缓冲区管理] 5 A --> D[流复用] 6 7 B --> E[连接池复用] 8 B --> F[请求对象复用] 9 B --> G[响应对象复用] 10 11 C --> H[Okio Buffer] 12 C --> I[Segment池] 13 C --> J[ByteString缓存] 14 15 D --> K[InputStream复用] 16 D --> L[OutputStream复用] 17 D --> M[Socket流复用] 18 19 subgraph "垃圾回收优化" 20 N[弱引用使用] 21 O[及时资源释放] 22 P[循环引用避免] 23 end 24 25 subgraph "内存监控" 26 Q[内存使用统计] 27 R[泄漏检测] 28 S[性能指标] 29 end 30 end 31
6.4.2 IO操作架构
1graph TB 2 subgraph "OkHttp IO架构" 3 A[应用层] --> B[OkHttp API] 4 B --> C[Interceptor Chain] 5 C --> D[Network Layer] 6 7 D --> E[Okio] 8 E --> F[BufferedSource] 9 E --> G[BufferedSink] 10 11 F --> H[Source] 12 G --> I[Sink] 13 14 H --> J[Socket InputStream] 15 I --> K[Socket OutputStream] 16 17 subgraph "缓冲优化" 18 L[Segment Buffer] 19 M[零拷贝操作] 20 N[批量读写] 21 end 22 23 subgraph "压缩优化" 24 O[GZip压缩] 25 P[Deflate压缩] 26 Q[Brotli压缩] 27 end 28 29 F --> L 30 G --> L 31 C --> O 32 C --> P 33 end 34
07.使用示例说明
7.1 基本使用
1// 创建客户端 2OkHttpClient client = new OkHttpClient.Builder() 3 .connectTimeout(10, TimeUnit.SECONDS) 4 .readTimeout(30, TimeUnit.SECONDS) 5 .writeTimeout(30, TimeUnit.SECONDS) 6 .build(); 7 8// 构建请求 9Request request = new Request.Builder() 10 .url("https://api.example.com/data") 11 .header("Authorization", "Bearer token") 12 .build(); 13 14// 同步执行 15try (Response response = client.newCall(request).execute()) { 16 if (response.isSuccessful()) { 17 String result = response.body().string(); 18 // 处理响应数据 19 } 20} 21 22// 异步执行 23client.newCall(request).enqueue(new Callback() { 24 @Override 25 public void onFailure(Call call, IOException e) { 26 // 处理失败 27 } 28 29 @Override 30 public void onResponse(Call call, Response response) throws IOException { 31 if (response.isSuccessful()) { 32 String result = response.body().string(); 33 // 处理响应数据 34 } 35 } 36}); 37
7.2 高级配置
1OkHttpClient client = new OkHttpClient.Builder() 2 // 连接池配置 3 .connectionPool(new ConnectionPool(10, 5, TimeUnit.MINUTES)) 4 // 缓存配置 5 .cache(new Cache(cacheDir, 50 * 1024 * 1024)) // 50MB缓存 6 // 拦截器 7 .addInterceptor(new LoggingInterceptor()) 8 .addNetworkInterceptor(new NetworkInterceptor()) 9 // 重试配置 10 .retryOnConnectionFailure(true) 11 // 代理配置 12 .proxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress("proxy.example.com", 8080))) 13 // SSL配置 14 .sslSocketFactory(sslSocketFactory, trustManager) 15 .hostnameVerifier(hostnameVerifier) 16 .build(); 17
7.3 统计请求耗时
OkHttp如何进行各个请求环节的耗时统计呢?
- OkHttp 版本提供了EventListener接口,可以让调用者接收一系列网络请求过程中的事件,例如DNS解析、TSL/SSL连接、Response接收等。
- 通过继承此接口,调用者可以监视整个应用中网络请求次数、流量大小、耗时(比如dns解析时间,请求时间,响应时间等等)情况。
如何消耗记录时间
- 在OkHttp库中有一个EventListener类。该类是网络事件的侦听器。扩展这个类以监视应用程序的HTTP调用的数量、大小和持续时间。
- 所有启动/连接/获取事件最终将接收到匹配的结束/释放事件,要么成功(非空参数),要么失败(非空可抛出)。
- 比如,可以在开始链接记录时间;dns开始,结束等方法解析记录时间,可以计算dns的解析时间。
- 比如,可以在开始请求记录时间,记录connectStart,connectEnd等方法时间,则可以计算出connect连接时间。
OkHttp性能监控架构
1graph TB 2 subgraph "OkHttp性能监控架构" 3 A[EventListener] --> B[连接事件] 4 A --> C[DNS事件] 5 A --> D[请求事件] 6 A --> E[响应事件] 7 8 B --> F[连接开始] 9 B --> G[连接结束] 10 B --> H[连接获取] 11 B --> I[连接释放] 12 13 C --> J[DNS开始] 14 C --> K[DNS结束] 15 16 D --> L[请求开始] 17 D --> M[请求头发送] 18 D --> N[请求体发送] 19 20 E --> O[响应头接收] 21 E --> P[响应体接收] 22 E --> Q[响应结束] 23 24 subgraph "指标收集" 25 R[连接池统计] 26 S[请求延迟] 27 T[吞吐量统计] 28 U[错误率统计] 29 end 30 31 subgraph "性能分析" 32 V[热点分析] 33 W[瓶颈识别] 34 X[优化建议] 35 end 36 end 37
《OkHttp网络框架设计》 是转载文章,点击查看原文。