一、 OkHttp 简介
OkHttp 是一个高效的 HTTP 客户端,由 Square 公司开发,支持 Android 和 Java 应用。
核心特性
- HTTP/2 支持:多路复用、头部压缩等
- 连接池:减少请求延迟
- 透明 GZIP 压缩:减少下载大小
- 响应缓存:避免重复请求
- 自动重连:处理网络问题
- WebSocket 支持
二、基本使用
1. 添加依赖
implementation 'com.squareup.okhttp3:okhttp:4.12.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()) {
String responseBody = response.body().string();
System.out.println(responseBody);
}
}
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 {
if (response.isSuccessful()) {
String responseBody = response.body().string();
System.out.println(responseBody);
}
}
});
三、核心组件详解
1. OkHttpClient
OkHttpClient client = new OkHttpClient.Builder()
.connectTimeout(10, TimeUnit.SECONDS) // 连接超时
.writeTimeout(10, TimeUnit.SECONDS) // 写入超时
.readTimeout(30, TimeUnit.SECONDS) // 读取超时
.addInterceptor(new HttpLoggingInterceptor()) // 拦截器
.cache(new Cache(cacheDir, cacheSize)) // 缓存
.retryOnConnectionFailure(true) // 自动重连
.build();
2. Request 请求构建
// POST 请求
RequestBody formBody = new FormBody.Builder()
.add("username", "user")
.add("password", "pass")
.build();
// JSON 请求
MediaType JSON = MediaType.parse("application/json; charset=utf-8");
RequestBody jsonBody = RequestBody.create(
"{"name":"John"}",
JSON
);
// 文件上传
RequestBody fileBody = RequestBody.create(
file,
MediaType.parse("image/png")
);
RequestBody multipartBody = new MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart("file", "avatar.png", fileBody)
.build();
Request request = new Request.Builder()
.url(url)
.header("Authorization", "Bearer token") // 添加头部
.addHeader("User-Agent", "OkHttp Example")
.post(formBody) // GET、POST、PUT、DELETE 等
.build();
3. Response 响应处理
try (Response response = client.newCall(request).execute()) {
// 状态码
int statusCode = response.code();
// 响应头
Headers headers = response.headers();
String contentType = headers.get("Content-Type");
// 响应体
ResponseBody body = response.body();
String stringBody = body.string(); // 只能调用一次
InputStream inputStream = body.byteStream();
byte[] bytes = body.bytes();
// 判断响应类型
if (response.isSuccessful()) {
// 2xx 响应
} else if (response.isRedirect()) {
// 3xx 重定向
}
}
四、高级功能
1. 拦截器(Interceptors)
// 应用拦截器(处理请求/响应)
class LoggingInterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
// 请求前处理
long startTime = System.nanoTime();
Log.d("OkHttp", String.format("Sending request %s%n%s",
request.url(), request.headers()));
Response response = chain.proceed(request);
// 响应后处理
long endTime = System.nanoTime();
Log.d("OkHttp", String.format("Received response in %.1fms%n%s",
(endTime - startTime) / 1e6d, response.headers()));
return response;
}
}
// 网络拦截器(处理网络层请求/响应)
OkHttpClient client = new OkHttpClient.Builder()
.addInterceptor(new LoggingInterceptor()) // 应用拦截器
.addNetworkInterceptor(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();
// 强制使用缓存
Request request = new Request.Builder()
.url(url)
.cacheControl(new CacheControl.Builder()
.onlyIfCached()
.maxStale(7, TimeUnit.DAYS)
.build())
.build();
3. Cookie 管理
// 使用 CookieJar
CookieJar cookieJar = new CookieJar() {
private final Map<String, List<Cookie>> cookieStore =
new ConcurrentHashMap<>();
@Override
public void saveFromResponse(HttpUrl url, List<Cookie> cookies) {
cookieStore.put(url.host(), cookies);
}
@Override
public List<Cookie> loadForRequest(HttpUrl url) {
List<Cookie> cookies = cookieStore.get(url.host());
return cookies != null ? cookies : new ArrayList<>();
}
};
OkHttpClient client = new OkHttpClient.Builder()
.cookieJar(cookieJar)
.build();
4. 连接池管理
ConnectionPool connectionPool = new ConnectionPool(
5, // 最大空闲连接数
5, // 保持时间(分钟)
TimeUnit.MINUTES
);
OkHttpClient client = new OkHttpClient.Builder()
.connectionPool(connectionPool)
.build();
5. 认证处理
// 基本认证
Authenticator authenticator = (route, response) -> {
String credential = Credentials.basic("username", "password");
return response.request().newBuilder()
.header("Authorization", credential)
.build();
};
OkHttpClient client = new OkHttpClient.Builder()
.authenticator(authenticator)
.build();
6. WebSocket
Request request = new Request.Builder()
.url("ws://echo.websocket.org")
.build();
WebSocket webSocket = client.newWebSocket(request, new WebSocketListener() {
@Override
public void onOpen(WebSocket webSocket, Response response) {
webSocket.send("Hello!");
}
@Override
public void onMessage(WebSocket webSocket, String text) {
System.out.println("Received: " + text);
}
@Override
public void onClosing(WebSocket webSocket, int code, String reason) {
webSocket.close(1000, null);
}
});
五、最佳实践
1. 单例模式使用
public class OkHttpClientManager {
private static OkHttpClient instance;
public static OkHttpClient getInstance() {
if (instance == null) {
synchronized (OkHttpClientManager.class) {
if (instance == null) {
instance = new OkHttpClient.Builder()
.connectTimeout(10, TimeUnit.SECONDS)
.readTimeout(10, TimeUnit.SECONDS)
.writeTimeout(10, TimeUnit.SECONDS)
.build();
}
}
}
return instance;
}
}
2. 请求取消
// 创建可取消的请求
Call call = client.newCall(request);
// 执行请求
call.enqueue(callback);
// 取消请求
call.cancel();
3. 超时重试
class RetryInterceptor implements Interceptor {
private int maxRetry;
public RetryInterceptor(int maxRetry) {
this.maxRetry = maxRetry;
}
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
Response response = null;
IOException exception = null;
for (int i = 0; i <= maxRetry; i++) {
try {
response = chain.proceed(request);
if (response.isSuccessful()) {
return response;
}
} catch (IOException e) {
exception = e;
}
}
throw exception != null ? exception :
new IOException("Request failed after " + maxRetry + " retries");
}
}
4. 错误处理
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
if (call.isCanceled()) {
// 请求被取消
} else if (e instanceof SocketTimeoutException) {
// 超时
} else if (e instanceof ConnectException) {
// 连接失败
}
}
@Override
public void onResponse(Call call, Response response) throws IOException {
if (!response.isSuccessful()) {
switch (response.code()) {
case 401:
// 未授权
break;
case 404:
// 资源不存在
break;
case 500:
// 服务器错误
break;
}
}
}
});
六、性能优化建议
- 重用 OkHttpClient 实例:避免重复创建
- 合理设置超时时间:根据网络状况调整
- 使用连接池:默认已优化,无需特殊配置
- 启用 GZIP:自动处理,无需手动配置
- 合理使用缓存:减少重复请求
- 批量请求:减少连接次数
- 及时关闭 Response:避免资源泄漏
七、常见问题
1. 内存泄漏
- 确保在 Activity/Fragment 销毁时取消请求
- 避免持有 Context 引用
2. 线程安全问题
- OkHttpClient 是线程安全的
- 可在多线程环境中共享
3. 大文件下载
- 使用 ResponseBody.byteStream() 流式处理
- 避免一次性加载到内存
4. HTTPS 证书验证
// 信任所有证书(仅测试环境使用)
OkHttpClient client = new OkHttpClient.Builder()
.sslSocketFactory(createSSLSocketFactory(), trustAllCerts)
.hostnameVerifier((hostname, session) -> true)
.build();
八、与 Retrofit 配合使用
OkHttp 是 Retrofit 的底层实现,Retrofit 在 OkHttp 基础上提供了 REST API 的抽象层:
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.example.com/")
.client(okHttpClient) // 使用自定义的 OkHttpClient
.addConverterFactory(GsonConverterFactory.create())
.build();
OkHttp 是一个功能强大且灵活的 HTTP 客户端,通过合理配置和正确使用,可以显著提升应用的网络性能和用户体验。
九、核心知识点
下图清晰地展示了从发起请求到获得响应的完整逻辑,从宏观上把握 OkHttp 的工作流程:
flowchart TD
A["发起请求<br>(execute/enqueue)"] --> B{Dispatcher 调度请求}
B -- 同步请求 --> C[加入 runningSyncCalls 队列<br>直接执行]
B -- 异步请求 --> D{"是否满足并发条件?"}
D -- "是<br>(未超64请求/每Host未超5)" --> E[加入 runningAsyncCalls 队列<br>提交至线程池执行]
D -- 否 --> F[加入 readyAsyncCalls 等待队列]
E --> G[执行完成<br>触发 finished]
C --> G
F --> H[等待队列中的请求<br>在 finished 中<br>被 promoteAndExecute 激活]
H --> E
G --> I[构建并执行<br>拦截器责任链]
subgraph I ["拦截器责任链 (getResponseWithInterceptorChain)"]
direction LR
I1["应用拦截器<br>(自定义)"] --> I2[RetryAndFollowUpInterceptor<br>重试与重定向] --> I3[BridgeInterceptor<br>桥接补全头部] --> I4[CacheInterceptor<br>缓存处理] --> I5[ConnectInterceptor<br>建立/复用连接] --> I6["网络拦截器<br>(自定义)"] --> I7[CallServerInterceptor<br>发送请求/读取响应]
end
I --> J[返回最终 Response]
1. 拦截器责任链(Interceptor Chain)
这是OkHttp最核心的机制。责任链将网络请求分解为多个独立步骤(拦截器),每个拦截器处理特定任务。
下图展示了各个内置拦截器在请求过程中的职责与作用:
flowchart LR
A[发起请求] --> B[应用拦截器<br>全局请求/响应处理] --> C[重试与重定向拦截器<br>处理失败与重定向] --> D[桥接拦截器<br>补全Header/解压] --> E[缓存拦截器<br>查询/更新缓存] --> F{"缓存是否命中?"}
F -- 是 --> G[直接返回缓存响应]
F -- 否 --> H[连接拦截器<br>建立/复用TCP连接] --> I[网络拦截器<br>网络层监控] --> J[请求服务器拦截器<br>I/O读写]
G --> K[返回响应]
J --> K
2. 连接复用与连接池(ConnectionPool)
这是OkHttp性能优化的关键。连接池的核心逻辑是:在建立TCP连接前,会依次尝试从池中获取可用连接,顺序是:已分配的连接 -> 连接池匹配(无路由) -> 连接池匹配(有路由) -> 创建新连接 -> 再次确认。连接池会定期清理空闲连接(默认最多5个空闲连接,保活5分钟)以释放资源。
3. 调度器与线程池(Dispatcher)
Dispatcher 负责管理异步请求的调度,其内部维护着三个双端队列(runningAsyncCalls, readyAsyncCalls, runningSyncCalls)和一个线程池。
- 并发控制:默认最大并发请求数为 64,单个主机(Host)最大并发数为 5。
- 线程池:本质是一个
newCachedThreadPool,核心线程数为0,使用SynchronousQueue,能快速响应网络请求。
4. 核心设计模式
OkHttp优雅的架构离不开设计模式的应用:
- 责任链模式:核心,用于拦截器链
- 建造者模式:用于构建
OkHttpClient和Request等复杂对象 - 外观模式:
OkHttpClient封装了内部复杂子系统,提供统一接口 - 策略模式:体现在缓存策略(如
CacheStrategy)等方面
十、常见面试问答
具体可参考上面核心知识点
1. OkHttp工作流程(核心:拦截器链)
一句话概括:请求通过调度器进入拦截器责任链,依次处理,最终由服务器拦截器完成网络I/O。
详细流程如下:
-
请求调度:同步请求直接执行,异步请求由
Dispatcher管理 -
拦截器链处理(关键流程): 应用拦截器 → 重试拦截器 → 桥接拦截器 → 缓存拦截器 → 连接拦截器(建立/复用连接)→ 网络拦截器 → 服务器拦截器
-
返回响应:经过反向传递,最终返回给调用方
2. OkHttp连接复用实现
核心机制:连接池(ConnectionPool)
实现原理:
-
复用条件:相同主机(host + port + TLS配置)
-
查找顺序:
- 已分配的连接 → 连接池匹配(无路由) → 连接池匹配(有路由) → 创建新连接
-
连接管理:
- 默认最多保持5个空闲连接
- 空闲连接保活5分钟
- 定期清理超时空闲连接
性能优势:减少TCP握手和TLS握手开销,显著提升性能。
3. 应用拦截器 vs. 网络拦截器的区别
| 维度 | 应用拦截器(addInterceptor) | 网络拦截器(addNetworkInterceptor) |
|---|---|---|
| 位置 | 在重试/重定向拦截器之前 | 在连接建立之后,服务器拦截器之前 |
| 触发次数 | 一次(即使重试) | 多次(重试/重定向会重新触发) |
| 获取信息 | 原始请求,无网络细节 | 携带网络信息(连接、IP等) |
| 典型用途 | 添加全局Header、日志记录 | 监控网络数据、修改重试策略 |
4. Dispatcher的作用
核心职责:异步请求调度中心
具体功能:
-
队列管理:维护三个队列
runningAsyncCalls:正在执行的异步请求readyAsyncCalls:等待执行的异步请求runningSyncCalls:正在执行的同步请求
-
并发控制:
- 最大并发请求数:64个
- 单主机最大并发数:5个
-
线程池管理:使用
CachedThreadPool(核心线程数0,适合I/O密集型) -
调度逻辑:请求完成后自动从等待队列提升新请求
5. OkHttp中的设计模式
-
责任链模式(核心):拦截器链处理请求
-
建造者模式:构建
OkHttpClient、Request等复杂对象 -
外观模式:
OkHttpClient封装内部复杂子系统 -
策略模式:缓存策略(
CacheStrategy)
6. OkHttp缓存工作原理
负责组件:CacheInterceptor
缓存机制:
-
存储位置:磁盘LRU缓存(基于
DiskLruCache) -
缓存决策:遵循HTTP缓存标准
-
关键逻辑:
- 检查请求是否允许缓存(
Cache-Control头) - 计算缓存策略:网络请求、缓存响应或两者
- 处理条件请求(
If-Modified-Since等)
- 检查请求是否允许缓存(
-
缓存流程:
收到请求 → 检查缓存 → 缓存有效 → 直接返回 → 缓存无效/需要验证 → 发送条件请求 → 304(未修改) → 更新缓存后返回 → 200(新内容) → 更新缓存后返回
7. OkHttp网络监控方法
核心工具:自定义拦截器
监控实现:
// 网络拦截器(可监控实际网络数据)
class NetworkMonitorInterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
// 1. 获取网络层请求信息
Request request = chain.request();
Connection connection = chain.connection(); // 获取连接信息
long startNs = System.nanoTime();
// 2. 记录请求信息
logRequest(request, connection);
// 3. 继续请求
Response response = chain.proceed(request);
// 4. 记录响应信息
long tookMs = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startNs);
logResponse(response, tookMs, connection);
return response;
}
}
监控要点:
- 网络拦截器可获取:实际IP、连接协议、握手信息
- 应用拦截器适合:统计请求耗时、记录业务日志