OkHttp3 使用及原理分析
一、OkHttp3
OkHttp 是 Square 公司开发的一个高效的 HTTP 客户端,具有以下特点:
- 支持 HTTP/2,允许所有访问同一主机的请求共享一个 socket
- 连接池减少请求延迟
- 透明的 GZIP 压缩
- 响应缓存
- 请求失败自动重试
- 支持同步和异步调用
二、基本使用
1. 添加依赖
implementation 'com.squareup.okhttp3:okhttp:4.9.0'
2. 同步请求示例
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url("https://api.example.com/data")
.build();
try (Response response = client.newCall(request).execute()) {
if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);
System.out.println(response.body().string());
}
3. 异步请求示例
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url("https://api.example.com/data")
.build();
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
e.printStackTrace();
}
@Override
public void onResponse(Call call, Response response) throws IOException {
try (ResponseBody responseBody = response.body()) {
if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);
System.out.println(responseBody.string());
}
}
});
三、核心原理分析
1. 整体架构
OkHttp 的核心工作流程可以分为以下几个部分:
- 请求构建:通过
Request.Builder
构建请求 - 请求执行:通过
OkHttpClient
和RealCall
执行请求 - 链:请求通过一系列处理
- 连接管理:通过连接池管理 HTTP 连接
- 数据交换:通过
HttpCodec
读写数据
2. 机制
OkHttp 的核心是链,默认包含以下:
-
重试与重定向:
RetryAndFollowUpInterceptor
- 处理请求失败后的重试
- 处理重定向
-
桥接:
BridgeInterceptor
- 补全请求头(如 Content-Type, Content-Length, Host 等)
- 处理 Gzip 压缩
-
缓存:
CacheInterceptor
- 根据缓存策略处理缓存
- 返回缓存或更新缓存
-
连接:
ConnectInterceptor
- 建立与服务器的连接
- 从连接池获取或创建新连接
-
网络:
CallServerInterceptor
- 向服务器发送请求数据
- 从服务器读取响应数据
3. 连接池管理
OkHttp 使用 ConnectionPool
管理连接,具有以下特点:
- 默认最多保持 5 个空闲连接
- 每个空闲连接最多存活 5 分钟
- 复用相同地址的连接可减少延迟
4. 请求流程
- 通过
OkHttpClient.newCall()
创建RealCall
对象 - 调用
execute()
或enqueue()
方法发起请求 - 请求进入链处理
- 经过一系列处理后,最终由
CallServerInterceptor
完成网络请求 - 响应数据沿链返回
四、高级特性
1. 自定义
class LoggingInterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
long t1 = System.nanoTime();
System.out.println(String.format("Sending request %s on %s%n%s",
request.url(), chain.connection(), request.headers()));
Response response = chain.proceed(request);
long t2 = System.nanoTime();
System.out.println(String.format("Received response for %s in %.1fms%n%s",
response.request().url(), (t2 - t1) / 1e6d, response.headers()));
return response;
}
}
// 使用自定义
OkHttpClient client = new OkHttpClient.Builder()
.addInterceptor(new LoggingInterceptor())
.build();
2. 缓存配置
int cacheSize = 10 * 1024 * 1024; // 10 MB
Cache cache = new Cache(new File("cacheDir"), cacheSize);
OkHttpClient client = new OkHttpClient.Builder()
.cache(cache)
.build();
3. 超时设置
OkHttpClient client = new OkHttpClient.Builder()
.connectTimeout(10, TimeUnit.SECONDS)
.writeTimeout(10, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS)
.build();
五、常见问题
-
内存泄漏:确保在 Activity/Fragment 销毁时取消请求
private Call call; // 发起请求 call = client.newCall(request); call.enqueue(callback); // 取消请求 @Override protected void onDestroy() { if (call != null) { call.cancel(); } }
-
主线程网络请求:OkHttp 同步请求不能在主线程执行
-
HTTPS 证书验证:自定义
X509TrustManager
可实现自签名证书验证
六、性能优化建议
- 复用
OkHttpClient
实例(通常作为单例使用) - 合理设置连接池参数
- 根据业务需求配置缓存
- 使用合适的监控和优化网络请求
- 对大文件下载使用流式处理,避免内存溢出
OkHttp3 是一个功能强大且设计优雅的 HTTP 客户端,理解其工作原理有助于更好地使用和优化网络请求。
(www.nzw6.com)