OkHttp 的拦截器是其核心设计之一,通过 责任链模式 实现网络请求的模块化处理,开发者可以灵活地监控、修改请求和响应。以下是其工作原理和关键实现机制:
- 请求预处理:修改请求头、添加参数、加密数据。
- 响应处理:解压数据、缓存处理、错误重试。
- 监控统计:记录请求耗时、日志打印。
OkHttp 的拦截器分为 应用拦截器(Application Interceptors) 和 网络拦截器(Network Interceptors),整体流程如下:
sequenceDiagram
participant Client
participant Application Interceptors
participant Network Interceptors
participant Cache
participant Network
participant Server
Client->>Application Interceptors: 发起请求
Application Interceptors->>Network Interceptors: 处理请求(如添加Token)
Network Interceptors->>Cache: 检查缓存
alt 缓存命中
Cache-->>Network Interceptors: 返回缓存响应
else 缓存未命中
Network Interceptors->>Network: 发送网络请求
Network->>Server: 请求服务器
Server-->>Network: 返回响应
Network-->>Network Interceptors: 原始响应
end
Network Interceptors->>Application Interceptors: 处理响应(如解密)
Application Interceptors->>Client: 最终响应
OkHttp 通过 RealInterceptorChain 类实现责任链的传递,核心逻辑如下:
public interface Interceptor {
Response intercept(Chain chain) throws IOException;
}// RealInterceptorChain.java
public Response proceed(Request request) throws IOException {
// 1. 获取当前拦截器
Interceptor interceptor = interceptors.get(index);
// 2. 创建下一个责任链节点
RealInterceptorChain next = new RealInterceptorChain(interceptors, index + 1);
// 3. 执行当前拦截器并传递责任链
Response response = interceptor.intercept(next);
return response;
}| 拦截器 | 作用 |
|---|---|
RetryAndFollowUpInterceptor |
处理重定向和失败重试。 |
BridgeInterceptor |
补全请求头(如 Content-Type、Cookie)。 |
CacheInterceptor |
缓存管理(根据 Cache-Control 判断是否使用缓存)。 |
ConnectInterceptor |
建立 TCP/TLS 连接。 |
CallServerInterceptor |
最终发送请求并读取响应。 |
class LoggingInterceptor : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
val request = chain.request()
println("Request: ${request.url}")
val startTime = System.nanoTime()
val response = chain.proceed(request)
val duration = (System.nanoTime() - startTime) / 1e6
println("Response: ${response.code} in ${duration}ms")
return response
}
}class AuthInterceptor : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
val originalRequest = chain.request()
val newRequest = originalRequest.newBuilder()
.header("Authorization", "Bearer ${getToken()}")
.build()
return chain.proceed(newRequest)
}
}val client = OkHttpClient.Builder()
.addInterceptor(LoggingInterceptor()) // 应用拦截器
.addNetworkInterceptor(AuthInterceptor()) // 网络拦截器
.build()| 特性 | 应用拦截器 | 网络拦截器 |
|---|---|---|
| 添加方式 | addInterceptor() |
addNetworkInterceptor() |
| 调用时机 | 最早执行,即使命中缓存也会触发。 | 仅在发起网络请求时触发(缓存命中时不执行)。 |
| 可见数据 | 原始请求和最终响应。 | 包含网络层细节(如重定向后的请求头)。 |
| 适用场景 | 日志、全局参数添加。 | 网络层监控、压缩/解压。 |
由于 RequestBody 和 ResponseBody 是单向流,需通过 BufferedSource 读取并重新构建:
class DecryptInterceptor : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
val response = chain.proceed(chain.request())
val encryptedData = response.body?.source()?.readByteString()
val decryptedData = decrypt(encryptedData) // 自定义解密
return response.newBuilder()
.body(decryptedData.toResponseBody())
.build()
}
}在拦截器中直接返回响应,不调用 chain.proceed():
class MockInterceptor : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
if (isMockMode) {
return Response.Builder()
.request(chain.request())
.protocol(Protocol.HTTP_2)
.code(200)
.body("{\"data\":\"mocked\"}".toResponseBody())
.build()
}
return chain.proceed(chain.request())
}
}- 避免阻塞操作:拦截器中不要执行耗时任务(如数据库读写)。
- 复用对象:多次修改请求时,复用
Request.Builder减少内存分配。 - 缓存处理:网络拦截器中修改的请求可能影响缓存键,需谨慎操作。
- 设计模式:责任链模式实现模块化处理。
- 核心方法:
intercept(Chain chain)和chain.proceed()。 - 应用场景:日志、认证、加密、Mock 数据、性能监控等。
- 选择策略:
- 需要全局处理 → 应用拦截器
- 需要网络层细节 → 网络拦截器
通过拦截器,OkHttp 实现了高度可定制的网络请求流程,这是其相比其他网络库的核心优势之一。
OkHttp 是 Android 和 Java 平台的高性能 HTTP 客户端,其设计融合了 连接池复用、拦截器链、协议协商 等优化思想。以下是其核心工作原理的体系化拆解:
graph TD
A[应用层] -->|Request| B[拦截器链]
B --> C[连接层]
C --> D[协议层]
D --> E[网络层]
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder().url("https://api.example.com").build();
Call call = client.newCall(request);
call.enqueue(new Callback() { ... });- Call 封装:每个请求被封装为
RealCall对象,维护请求状态(如已取消)。 - 任务调度:通过
Dispatcher管理异步请求的线程池和同步请求队列。
OkHttp 的核心处理流程通过 5大内置拦截器 + 自定义拦截器 完成:
sequenceDiagram
participant App as 应用拦截器
participant Retry as RetryAndFollowUp
participant Bridge as Bridge
participant Cache as Cache
participant Connect as Connect
participant Network as NetworkInterceptors
participant CallServer as CallServer
App->>Retry: 原始请求
Retry->>Bridge: 补全头部
Bridge->>Cache: 检查缓存
alt 缓存命中
Cache-->>Bridge: 返回缓存
else 未命中
Cache->>Connect: 建立连接
Connect->>Network: 网络拦截器
Network->>CallServer: 发送请求
CallServer-->>Network: 原始响应
end
Network-->>Connect: 响应
Connect-->>Cache: 缓存响应
Cache-->>Bridge: 响应
Bridge-->>Retry: 处理重定向
Retry-->>App: 最终响应
- 连接池(ConnectionPool):默认维护 5 个空闲连接,存活时间 5 分钟。
- 复用判断条件:
- 相同主机和端口
- 相同的 TLS 配置
- 连接未关闭
- 优势:减少 TCP/TLS 握手开销,提升吞吐量。
- 支持协议:HTTP/1.1、HTTP/2、QUIC(实验性)。
- 协商过程:
- 首次连接尝试 HTTP/2(如果服务器支持 ALPN)。
- 失败后降级到 HTTP/1.1。
// 从连接池获取或新建连接
RealConnection connection = connectionPool.transmitter.acquireConnection(
eventListener, transmitter.timeout);// 写入请求头
httpCodec.writeRequestHeaders(request);
// 发送请求体(如有)
if (HttpMethod.permitsRequestBody(request.method())) {
BufferedSink bufferedRequestBody = Okio.buffer(
httpCodec.createRequestBody(request, contentLength));
requestBody.writeTo(bufferedRequestBody);
}
// 读取响应
response = httpCodec.readResponseHeaders(false);// 检查缓存
Response cacheCandidate = cache != null ? cache.get(chain.request()) : null;
// 根据Cache-Control决定是否使用缓存
if (cacheResponse != null) {
return cacheResponse.newBuilder()
.cacheResponse(stripBody(cacheResponse))
.build();
}| 优化点 | 实现方式 |
|---|---|
| 连接复用 | 基于 Host 的连接池管理,支持 HTTP/2 多路复用。 |
| 请求压缩 | 自动添加 Accept-Encoding: gzip,响应体自动解压。 |
| 零拷贝优化 | 使用 Okio 的 BufferedSource 减少内存拷贝。 |
| DNS 优化 | 支持自定义 Dns 实现(如 HTTPDNS)。 |
| 超时控制 | 分级别设置连接、读取、写入超时。 |
- 网络异常:通过
RetryAndFollowUpInterceptor实现自动重试(默认最大 20 次)。 - 证书校验:
CertificatePinner防止中间人攻击。 - 代理支持:自动识别系统代理设置。
| 特性 | OkHttp | HttpURLConnection | Volley |
|---|---|---|---|
| 连接复用 | ✅ 支持 | ❌ 部分支持 | ✅ 支持 |
| HTTP/2 | ✅ 完整支持 | ❌ 不支持 | ❌ 不支持 |
| 拦截器 | ✅ 灵活扩展 | ❌ 无 | ❌ 无 |
| 缓存控制 | ✅ 精细管理 | ✅ 基础支持 | ✅ 自动缓存 |
// 共享连接池和线程池
public class OkHttpSingleton {
private static final OkHttpClient instance = new OkHttpClient.Builder()
.connectionPool(new ConnectionPool(10, 5, TimeUnit.MINUTES))
.build();
public static OkHttpClient getInstance() {
return instance;
}
}val client = OkHttpClient.Builder()
.addNetworkInterceptor(ProgressInterceptor { bytesRead, contentLength ->
val percent = bytesRead * 100f / contentLength
println("下载进度: ${"%.1f".format(percent)}%")
})
.build()- 分层设计:各司其职的拦截器链。
- 资源复用:连接池、线程池优化。
- 协议透明:自动选择最佳传输协议。
- 扩展性:拦截器机制支持功能插件化。
OkHttp 通过上述设计实现了 高性能、低延迟、高可靠性 的网络通信,成为 Android 开发的事实标准网络库。