OkHttp-HTTP 客户端框架
plaintext请求发起(Call.execute()/enqueue())→ 应用拦截器链(用户自定义)→ 重定向/重试处理→ 桥接处理(默认头、GZIP)→ 缓存处理(命中缓存则直接返回,否则继续)→ 连接建立(连接池复用或新建)→ 网络拦截器链(用户自定义)→ 与服务器通信(发送请求、接收响应)→ 反向返回响应(按拦截器链倒序处理,缓存拦截器更新缓存、桥接拦截器解压等)→ 响应返回给调用者
·
一、OkHttp 定位
OkHttp 是由 Square 公司开源的一款高效、轻量级的 HTTP 客户端,支持 Android 和 Java 平台,目前是 Android 开发中最主流的网络请求框架之一(Retrofit 底层也默认依赖 OkHttp 实现网络请求)。
它的设计目标是简化 HTTP 请求操作,提升网络请求性能,处理常见的网络问题(如连接超时、重定向、缓存等),让开发者无需关注底层复杂的网络细节,专注于业务逻辑实现。
二、核心特性
- 支持多种 HTTP 协议版本:默认支持 HTTP/1.1、HTTP/2,可选支持 HTTP/3(QUIC),HTTP/2 支持多路复用,可在单个连接上并发多个请求,大幅提升并发性能。
- 连接池复用:内置高效的连接池(
ConnectionPool),复用已建立的 TCP 连接,避免频繁创建 / 销毁连接带来的性能开销(默认保持 5 个空闲连接,存活时间 5 分钟)。 - 透明的数据压缩:自动对请求体和响应体进行 GZIP 压缩,减少网络传输的数据量,提升请求速度。
- 强大的请求缓存机制:支持 HTTP 缓存规范,可缓存响应数据,在无网络或缓存未过期时直接读取本地缓存,减少网络请求,提升离线体验。
- 灵活的超时与重试机制:支持设置连接超时、读取超时、写入超时,自动处理常见的网络错误(如连接失败、重试可用的请求),提升请求的容错性。
- 拦截器机制:提供强大的拦截器链(Interceptor Chain),支持自定义请求 / 响应的处理逻辑(如添加公共请求头、打印日志、Token 刷新、数据加密等)。
- 安全的 HTTPS 支持:默认支持 HTTPS,提供证书验证、自定义证书、忽略证书(仅测试环境使用)等功能,保障网络传输的安全性。
- 便捷的请求取消:支持单个请求取消或批量请求取消,避免无用请求占用资源。
- 建造者模式封装:请求(
Request)、客户端(OkHttpClient)均采用建造者模式构建,API 简洁易用,可读性强。
三、核心组件
OkHttp 的核心组件相互配合完成网络请求,关键组件如下:
1. OkHttpClient
- 核心:OkHttp 的客户端实例,相当于一个 "网络请求工厂",负责创建和执行
Call对象。 - 特性:采用建造者模式(
OkHttpClient.Builder)创建,包含连接池、拦截器、超时时间、缓存等所有全局配置。 - 最佳实践:推荐全局单例使用,因为创建
OkHttpClient会初始化连接池、线程池等资源,频繁创建会造成资源浪费和性能下降。
2. Request
- 核心:表示一个 HTTP 请求对象,包含请求的 URL、请求方法(GET/POST/PUT 等)、请求头、请求体、缓存策略等信息。
- 特性:同样采用建造者模式(
Request.Builder)构建,一个Request对应一个具体的网络请求。 - 关键属性:
url():设置请求 URL。method():设置请求方法(默认 GET)。header()/headers():设置单个 / 多个请求头。body():设置请求体(仅 POST、PUT 等方法需要)。cacheControl():设置缓存策略(如强制缓存、禁止缓存)。
3. Response
- 核心:表示一个 HTTP 响应对象,是服务器返回的结果封装,包含响应码、响应头、响应体、缓存信息、请求对应的
Request等。 - 关键属性:
code():HTTP 响应码(200 表示成功、404 表示未找到、500 表示服务器错误等)。message():响应消息描述。headers():响应头信息。body():响应体(ResponseBody),包含服务器返回的实际数据(如 JSON、文件流等)。cacheResponse():缓存的响应(若命中缓存)。networkResponse():网络获取的响应(若从网络请求)。
4. ResponseBody
- 核心:封装 HTTP 响应的实际数据,是一次性资源,使用后必须关闭,否则会造成资源泄漏。
- 常用方法:
string():将响应体转换为 UTF-8 编码的字符串(适合小数据,如 JSON)。bytes():将响应体转换为字节数组(适合二进制小数据)。byteStream():获取响应体的输入流(适合大数据,如文件下载)。contentType():获取响应体的媒体类型(如application/json、image/jpeg)。
- 关闭方式:可通过
close()手动关闭,或使用 try-with-resources 语法(Java 7+)自动关闭。
5. Call
- 核心:表示一个已经准备好执行的请求 / 响应会话,是连接
Request和Response的桥梁。 - 创建方式:通过
OkHttpClient.newCall(Request)创建。 - 两种执行方式:
- 同步执行:
execute(),在当前线程阻塞执行,返回Response,不可在 Android 主线程执行(会阻塞 UI)。 - 异步执行:
enqueue(Callback),将请求加入请求队列,在 OkHttp 的线程池中执行,执行结果通过Callback回调返回(不会阻塞当前线程)。
- 同步执行:
- 其他方法:
cancel()(取消请求)、isCanceled()(判断是否已取消)、request()(获取对应的Request)。
6. Interceptor(拦截器)
- 核心:拦截器是 OkHttp 的核心扩展点,采用责任链模式,可以在请求发送前、响应返回后对请求 / 响应进行处理。
- 两种类型的拦截器(核心区别):
类型 应用拦截器(Application Interceptor) 网络拦截器(Network Interceptor) 添加方式 OkHttpClient.Builder.addInterceptor()OkHttpClient.Builder.addNetworkInterceptor()执行时机 仅在应用层执行,早于所有网络相关逻辑 在网络层执行,介于连接建立后和服务器通信前 执行次数 无论是否重定向、重试,仅执行 1 次 每次网络请求都会执行(重定向、重试时会多次执行) 可获取信息 仅能获取应用层的请求 / 响应,无法获取网络连接细节 可获取网络层的细节(如真实的请求 URL、连接信息) 适用场景 添加公共请求头、打印完整请求日志、Token 刷新、数据加密 监控网络传输数据、修改网络层请求 / 响应、统计网络耗时 - 核心方法:
intercept(Chain chain),Chain表示拦截器链,通过chain.proceed(request)将请求传递给下一个拦截器,最终获取响应。
7. ConnectionPool(连接池)
- 核心:负责管理 HTTP 连接的复用,减少 TCP 连接的创建开销。
- 默认配置:最多保持 5 个空闲连接,空闲连接存活时间 5 分钟。
- 自定义配置:可通过
OkHttpClient.Builder.connectionPool(ConnectionPool)修改,如:java
运行
ConnectionPool connectionPool = new ConnectionPool(10, 30, TimeUnit.SECONDS); OkHttpClient client = new OkHttpClient.Builder() .connectionPool(connectionPool) .build();
四、OkHttp 工作流程(核心:拦截器链)
OkHttp 的请求执行核心是拦截器链,一个请求从发起到获取响应,会依次经过以下拦截器(按执行顺序):
- 应用拦截器:用户添加的应用拦截器(按添加顺序执行)。
- 重定向 / 重试拦截器(
RetryAndFollowUpInterceptor):处理请求重定向(如 301、302)和请求重试(如连接失败)。 - 桥接拦截器(
BridgeInterceptor):处理应用层和网络层的桥接,如添加默认请求头(User-Agent、Accept-Encoding)、处理 GZIP 解压、处理缓存头。 - 缓存拦截器(
CacheInterceptor):处理 HTTP 缓存,判断是否命中缓存、是否需要更新缓存、是否可以直接使用缓存。 - 连接拦截器(
ConnectInterceptor):从连接池中获取或创建新的 TCP 连接,建立与服务器的连接。 - 网络拦截器:用户添加的网络拦截器(按添加顺序执行)。
- 服务端通信拦截器(
CallServerInterceptor):最终的拦截器,负责向服务器发送请求数据、读取服务器响应数据,完成实际的网络通信。
流程总结
plaintext
请求发起(Call.execute()/enqueue())
→ 应用拦截器链(用户自定义)
→ 重定向/重试处理
→ 桥接处理(默认头、GZIP)
→ 缓存处理(命中缓存则直接返回,否则继续)
→ 连接建立(连接池复用或新建)
→ 网络拦截器链(用户自定义)
→ 与服务器通信(发送请求、接收响应)
→ 反向返回响应(按拦截器链倒序处理,缓存拦截器更新缓存、桥接拦截器解压等)
→ 响应返回给调用者
五、基本使用示例
1. 准备工作:添加依赖
Gradle(Android/Java)
gradle
// 最新版本可查看OkHttp官方仓库:https://github.com/square/okhttp
implementation 'com.squareup.okhttp3:okhttp:4.12.0'
// 若需要打印日志,可添加官方日志拦截器
implementation 'com.squareup.okhttp3:logging-interceptor:4.12.0'
Maven
xml
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>4.12.0</version>
</dependency>
2. 核心步骤
- 构建
OkHttpClient实例(单例)。 - 构建
Request实例。 - 创建
Call实例并执行(同步 / 异步)。 - 处理
Response响应(关闭ResponseBody)。
3. 具体示例
示例 1:异步 GET 请求(推荐,不阻塞线程)
java
运行
// 1. 构建OkHttpClient单例(全局唯一)
private static final OkHttpClient OK_HTTP_CLIENT = new OkHttpClient.Builder()
.connectTimeout(10, TimeUnit.SECONDS) // 连接超时
.readTimeout(10, TimeUnit.SECONDS) // 读取超时
.writeTimeout(10, TimeUnit.SECONDS) // 写入超时
.build();
// 2. 发起异步GET请求
public void asyncGetRequest(String url) {
// 构建Request
Request request = new Request.Builder()
.url(url)
.get() // 默认就是GET,可省略
.header("User-Agent", "OkHttp-Demo")
.build();
// 3. 创建Call并执行异步请求
Call call = OK_HTTP_CLIENT.newCall(request);
call.enqueue(new Callback() {
// 请求失败回调
@Override
public void onFailure(@NonNull Call call, @NonNull IOException e) {
e.printStackTrace();
// 处理失败逻辑(如提示用户网络错误)
}
// 请求成功回调
@Override
public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
// 4. 处理响应(注意:onResponse在子线程执行,Android中更新UI需切换到主线程)
if (response.isSuccessful()) { // isSuccessful() 等价于 response.code() >= 200 && response.code() < 300
// 读取响应体(try-with-resources自动关闭ResponseBody)
try (ResponseBody responseBody = response.body()) {
if (responseBody != null) {
String result = responseBody.string();
// 处理成功数据(如解析JSON)
System.out.println("响应结果:" + result);
}
}
} else {
System.out.println("请求失败,响应码:" + response.code());
}
}
});
}
示例 2:同步 POST 请求(表单提交)
java
运行
public String syncPostRequest(String url) throws IOException {
// 1. 构建表单请求体
RequestBody formBody = new FormBody.Builder()
.add("username", "test")
.add("password", "123456")
.build();
// 2. 构建Request
Request request = new Request.Builder()
.url(url)
.post(formBody)
.build();
// 3. 同步执行请求(阻塞当前线程,不可在Android主线程执行)
try (Response response = OK_HTTP_CLIENT.newCall(request).execute()) {
// 4. 处理响应
if (response.isSuccessful() && response.body() != null) {
return response.body().string();
} else {
throw new IOException("请求失败,响应码:" + response.code());
}
}
}
六、高级特性
1. 自定义拦截器(日志打印)
java
运行
// 自定义应用拦截器,打印请求/响应日志
public class LoggingInterceptor implements Interceptor {
@NonNull
@Override
public Response intercept(@NonNull Chain chain) throws IOException {
// 请求发送前:打印请求信息
Request request = chain.request();
long startTime = System.currentTimeMillis();
System.out.println(String.format("发送请求:%s %s%n请求头:%s",
request.method(), request.url(), request.headers()));
// 传递请求到下一个拦截器,获取响应
Response response = chain.proceed(request);
// 响应返回后:打印响应信息
long endTime = System.currentTimeMillis();
System.out.println(String.format("接收响应:%s %n响应码:%d%n响应头:%s%n耗时:%dms",
response.request().url(), response.code(), response.headers(), (endTime - startTime)));
return response;
}
}
// 添加拦截器到OkHttpClient
OkHttpClient client = new OkHttpClient.Builder()
.addInterceptor(new LoggingInterceptor()) // 应用拦截器
// .addNetworkInterceptor(new LoggingInterceptor()) // 网络拦截器
.build();
2. 配置缓存
java
运行
// 指定缓存目录和缓存大小(50MB)
File cacheDir = new File(Environment.getExternalStorageDirectory(), "OkHttpCache");
Cache cache = new Cache(cacheDir, 50 * 1024 * 1024); // 50MB
OkHttpClient client = new OkHttpClient.Builder()
.cache(cache)
// 自定义缓存策略(强制缓存10分钟)
.addInterceptor(chain -> {
Request request = chain.request();
// 无网络时强制使用缓存
if (!isNetworkAvailable()) {
request = request.newBuilder()
.cacheControl(CacheControl.FORCE_CACHE)
.build();
}
Response response = chain.proceed(request);
// 有网络时,缓存10分钟
CacheControl cacheControl = new CacheControl.Builder()
.maxAge(10, TimeUnit.MINUTES)
.build();
return response.newBuilder()
.header("Cache-Control", cacheControl.toString())
.removeHeader("Pragma") // 移除旧的缓存头
.build();
})
.build();
3. 文件上传(MultipartBody)
java
运行
public void uploadFile(String url, File file) {
// 构建多部分请求体(表单+文件)
RequestBody requestBody = new MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart("description", "测试文件上传")
.addFormDataPart("file", file.getName(),
RequestBody.create(MediaType.parse("application/octet-stream"), file))
.build();
Request request = new Request.Builder()
.url(url)
.post(requestBody)
.build();
OK_HTTP_CLIENT.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(@NonNull Call call, @NonNull IOException e) {
e.printStackTrace();
}
@Override
public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
if (response.isSuccessful()) {
System.out.println("文件上传成功:" + response.body().string());
}
}
});
}
七、最佳实践与注意事项
OkHttpClient单例化:全局只创建一个OkHttpClient实例,避免重复创建连接池、线程池等资源,造成性能浪费。- 必须关闭
ResponseBody:ResponseBody是一次性资源,持有底层的 IO 流,使用后必须关闭(推荐使用 try-with-resources 语法),否则会造成内存泄漏和连接池阻塞。 - 避免主线程执行同步请求:
Call.execute()是阻塞方法,在 Android 主线程执行会导致 ANR(应用无响应),仅可在子线程中使用。 - 异步回调切换主线程:
Call.enqueue()的回调方法(onFailure/onResponse)在 OkHttp 的子线程执行,Android 中若需要更新 UI,需通过Handler、LiveData、RxJava等切换到主线程。 - 合理配置超时时间:根据业务场景配置连接、读取、写入超时(一般 10-30 秒),避免超时时间过短导致正常请求失败,或过长导致无用请求阻塞。
- 拦截器区分使用场景:添加公共请求头、Token 刷新等使用应用拦截器;监控网络传输、统计网络耗时等使用网络拦截器。
- HTTPS 安全配置:正式环境中不要忽略证书验证,应使用自定义证书或信任系统默认证书,避免安全风险。
- 大文件处理:下载大文件时,使用
ResponseBody.byteStream()获取输入流,分块写入本地文件,避免使用string()或bytes()直接加载到内存,造成 OOM。
总结
- OkHttp 是高效、易用的 HTTP 客户端,支持 Android/Java,是 Retrofit 的底层依赖,核心优势是连接复用、拦截器机制、缓存支持。
- 核心组件:
OkHttpClient(客户端)、Request(请求)、Response(响应)、Call(请求会话)、Interceptor(拦截器)。 - 工作核心:拦截器链,请求依次经过应用拦截器、重定向、桥接、缓存、连接、网络拦截器、服务端通信,反向返回响应。
- 最佳实践:单例化
OkHttpClient、关闭ResponseBody、避免主线程同步请求、合理使用拦截器。
更多推荐


所有评论(0)