OkHttp源码梳理
目录
一、基本使用
1 创建 OkHttpClient
2 构建请求 Request
3 创建和执行 Call
二、OkHttp请求整体流程
1. 用户调用入口
2. RealCall执行逻辑
2.1 同步请求:RealCall.execute()
2.2 异步请求:RealCall.enqueue(Callback)
3. Dispatcher调度请求
4. 拦截器链 getResponseWithInterceptorChain()
三、OkHttp 内置 Interceptor 总结
1. 重试与重定向拦截器(RetryAndFollowUpInterceptor)
2. 桥接拦截器(BridgeInterceptor)
3. 缓存拦截器(CacheInterceptor)
4. 连接拦截器(ConnectInterceptor)
5. 网络拦截器(CallServerInterceptor)
一、基本使用
1 创建 OkHttpClient
-
全局配置中心
-
可以通过
Builder
配置:-
连接超时、读写超时
-
连接池(ConnectionPool)
-
拦截器(Interceptor)
-
事件监听(EventListener)
-
代理设置、证书配置等
-
2 构建请求 Request
Request用于描述单次请求的参数信息,支持各种 HTTP 方法(GET、POST、PUT、DELETE...),也可以带 Header、Body。
3 创建和执行 Call
-
Call
是一次请求的抽象。 -
可以同步 (
execute
) 或异步 (enqueue
) 执行。 -
同步请求,会阻塞线程,不能直接在主线程当中调用
-
异步请求默认在子线程,自己切换线程。
二、OkHttp请求整体流程
1. 用户调用入口
无论是同步请求(execute()
),还是异步请求(enqueue()
),都是从RealCall开始的:
-
OkHttpClient.newCall(Request)
:返回一个RealCall
。 -
RealCall
是 OkHttp 处理每个请求的真正执行类。
2. RealCall
执行逻辑
2.1 同步请求:RealCall.execute()
2.2 异步请求:RealCall.enqueue(Callback)
-
okhttp会把异步请求包装成一个 AsyncCall
-
AsyncCall实现了Runnable接口,重写了run方法,并在run方法中调getResponseWithInterceptorChain()
3. Dispatcher调度请求
-
同步:直接加入
runningSyncCalls
。 -
异步:
-
先加入
readyAsyncCalls
等待排队, -
再调用promoteAndExecute()函数从异步任务等待队列选举任务并执行,选举时遍历等待队列,检查当前总请求数有没有达到上限,当前同一主机名请求数有没有达到上限,通过后交给线程池执行
-
最终都会执行 getResponseWithInterceptorChain()
,进入真正的拦截器链处理流程。
4. 拦截器链 getResponseWithInterceptorChain()
该方法会按一定的顺序构建拦截器列表interceptors
,接着利用interceptors
创建RealInterceptorChain
对象,该对象是一条责任链,使用了责任链模式。
请求从上往下交付,每个拦截器拿到请求都可以对请求做出相应处理,然后交给下一个拦截器,最后一个拦截器处理请求拿到响应后,将响应从下往上交付,每个拦截器拿到响应后再对响应做出相应处理,然后交给上一个拦截器。
拦截器 | 作用 |
---|---|
用户自定义应用拦截器 | 可以操作请求/响应,记录日志,加签名认证等 |
RetryAndFollowUpInterceptor | 负责失败重试、重定向 |
BridgeInterceptor | 请求标准化,响应标准化,添加必要头部,响应体解码 |
CacheInterceptor | 读取缓存,更新缓存 |
ConnectInterceptor | 建立与服务器的连接 |
用户自定义网络拦截器 | 观察实际请求/响应报文(仅对真正走网络的请求) |
CallServerInterceptor | 发送请求到服务器、接收响应 |
三、OkHttp 内置 Interceptor 总结
1. 重试与重定向拦截器(RetryAndFollowUpInterceptor)
- 作用:处理请求失败时的自动重试和 HTTP 重定向(如 302 跳转)。
- 关键行为:
- 检测可恢复的异常(如连接超时、Socket 断开)并重试请求。
- 遵循 HTTP 协议的重定向响应(如 301/302/307),自动跳转到新 URL。
- 限制最大重试次数(默认 20 次)和重定向次数。
- 示例场景:
// 当服务器返回 302 时,自动请求新的 Location 地址 Response response = client.newCall(request).execute(); // 无需手动处理跳转
2. 桥接拦截器(BridgeInterceptor)
- 作用:在应用代码和网络请求之间“桥接”,补充必要协议头并处理响应解码。
- 关键行为:
- 自动添加缺失的 HTTP 头(如
Host
、Content-Type
、Accept-Encoding: gzip
)。 - 处理
CookieJar
的自动注入(如果配置了 Cookie 管理器)。 - 解压 Gzip 压缩的响应体(透明解压,对应用层无感知)。
- 自动添加缺失的 HTTP 头(如
- 示例补充的请求头:
Accept-Encoding: gzip User-Agent: okhttp/4.10.0 Connection: keep-alive
3. 缓存拦截器(CacheInterceptor)
- 作用:根据 HTTP 缓存策略管理本地缓存,减少重复网络请求。
- 关键行为:
- 检查请求是否符合缓存条件(如
Cache-Control
头)。 - 返回缓存响应(如果未过期且有效)。
- 缓存服务器返回的新响应(如果配置了缓存目录)。
- 检查请求是否符合缓存条件(如
- 缓存配置示例:
OkHttpClient client = new OkHttpClient.Builder().cache(new Cache(new File("cacheDir"), 10 * 1024 * 1024)) // 10MB 缓存.build();
4. 连接拦截器(ConnectInterceptor)
- 作用:建立与目标服务器的 TCP/TLS 连接(或复用连接池中的连接)。
- 关键行为:
- 从连接池中复用空闲连接(减少 TCP 握手开销)。
- 必要时创建新连接(支持 HTTP/1.1、HTTP/2 或 WebSocket)。
- 处理 TLS 握手(HTTPS 请求)。
- 性能优化:
- 默认连接池最多维护 5 个空闲连接,存活时间 5 分钟。
5. 网络拦截器(CallServerInterceptor)
- 作用:最终向服务器发送请求数据并读取响应,完成网络 I/O 操作。
- 关键行为:
- 写入请求头和请求体(通过 Socket 输出流)。
- 读取响应头和响应体(通过 Socket 输入流)。
- 处理分块传输编码(
Transfer-Encoding: chunked
)。 - 关闭连接(如果未启用
keep-alive
)。
- 底层细节:
- 使用 Okio 库高效读写数据流。