【Java知识】OkHttp一款优秀的http客户端工具
OkHttp一款优秀的http客户端工具
- OkHttp概述
- 一、OkHttp 的核心优势
- 二、核心源码解析(以 OkHttp 4.9.3 为例)
- 1. 请求构建与执行流程
- 2. 连接池管理(高并发关键)
- 3. 拦截器链(责任模式)
- 三、完整使用样例
- 1. 高并发配置
- 2. 资源隔离(多服务独立连接池)
- 3. 异常处理与重试
- 四、源码设计亮点
- 五、适用场景
- OkHttp工作机制解析
- 一、整体流程概览
- 二、核心工作机制详解
- 1. **请求创建与封装**
- 2. **请求调度(Dispatcher)**
- 3. **拦截器链处理(InterceptorChain)**
- 4. **网络通信与连接管理**
- 5. **响应处理与回调**
- 三、关键源码解析
- 1. **RealCall 执行流程**
- 2. **Dispatcher 任务调度**
- 四、性能优化与高并发策略
- 1. **连接复用**
- 2. **线程池调优**
- 3. **异步回调优化**
- 五、异常处理与重试机制
- 1. **RetryAndFollowUpInterceptor**
- 2. **自定义重试策略**
- 六、总结
- OkHttp的拦截器分类以及作用
- 一、内置拦截器(OkHttp 原生实现)
- 1. **RetryAndFollowUpInterceptor**
- 2. **BridgeInterceptor**
- 3. **CacheInterceptor**
- 4. **ConnectInterceptor**
- 5. **CallServerInterceptor**
- 二、自定义拦截器(开发者实现)
- 1. **应用拦截器(Application Interceptor)**
- 2. **网络拦截器(Network Interceptor)**
- 三、拦截器执行流程示例
- 四、拦截器设计模式解析
- 五、典型应用场景
- 六、注意事项
- OkHttp实现请求与响应的加解密(拦截器的使用)
- 一、实现原理
- 二、核心代码实现
- 1. 请求加密拦截器(AES 加密)
- 2. 响应解密拦截器(AES 解密)
- 3. 集成到 OkHttpClient
- 三、高级场景实现
- 1. **混合加密(RSA + AES)**
- 2. **URL 参数加密**
- 3. **动态密钥管理**
- 四、异常处理与安全增强
- 1. **异常捕获**
- 2. **证书校验**
- 五、性能优化
- 六、完整使用示例
- 七、注意事项
- OkHttp实现GZIP压缩
- 一、GZIP 压缩的实现原理
- 二、请求压缩的配置
- 1. 添加 GZIP 请求拦截器
- 2. 配置 OkHttpClient
- 三、响应解压的自动处理
- 四、高级配置与优化
- 1. 动态压缩级别控制
- 2. 压缩策略优化
- 五、完整使用示例
- 1. 添加依赖(Maven)
- 2. 配置客户端与发送请求
- 六、注意事项
- 七、性能测试对比
OkHttp概述
在 Java 生态中,OkHttp 是使用最广泛的 HTTP 客户端库之一,尤其在 Android 和后端服务中占据主导地位。以下从核心优势、源码解析、使用样例(含高并发、资源隔离和异常处理)进行深度解析:
一、OkHttp 的核心优势
-
高性能
- 连接池复用:通过
ConnectionPool复用 TCP 连接,减少握手开销(HTTP/1.1 和 HTTP/2 多路复用)。 - 零拷贝流式处理:使用
BufferedSource和BufferedSink避免内存复制,提升吞吐量。 - 异步非阻塞:基于线程池和事件驱动模型,高效处理高并发请求。
- 连接池复用:通过
-
可扩展性
- 拦截器机制:支持自定义拦截器(如日志、认证、重试),灵活扩展功能。
- 与主流框架集成:如 Retrofit、Spring 等,无缝对接微服务架构。
-
安全性
- 支持 TLS 1.3、证书 Pinning,自动处理证书校验和证书透明性(Certificate Transparency)。
二、核心源码解析(以 OkHttp 4.9.3 为例)
1. 请求构建与执行流程
// 核心类:OkHttpClient
public final class OkHttpClient implements Cloneable {// 连接池管理final ConnectionPool connectionPool;// 线程池配置final Dispatcher dispatcher;// 拦截器链final List<Interceptor> interceptors;// 构建请求public Call newCall(Request request) {return RealCall.newRealCall(this, request, false);}
}// 请求执行类:RealCall
final class RealCall implements Call {// 执行请求的核心方法@Override public Response execute() throws IOException {// 1. 检查是否已执行checkNotExecuted();// 2. 获取连接Transmitter transmitter = acquireTransmitter();// 3. 发送请求return transmitter.sendRequest();}
}
2. 连接池管理(高并发关键)
// ConnectionPool 源码
public final class ConnectionPool {private final Queue<RealConnection> connections = new ConcurrentLinkedQueue<>();private final int maxIdleConnections; // 最大空闲连接数private final long keepAliveDuration; // 连接存活时间// 获取可用连接RealConnection get(ConnectionSpec spec) {for (RealConnection connection : connections) {if (connection.isAlive() && spec.isCompatible(connection.route().protocol())) {return connection;}}return null;}
}
3. 拦截器链(责任模式)
// 拦截器接口
public interface Interceptor {Response intercept(Chain chain) throws IOException;
}// 拦截器链执行
class RealInterceptorChain implements Interceptor.Chain {private final List<Interceptor> interceptors;private final int index;private final Request request;public Response proceed(Request request) {// 递归执行拦截器链if (index < interceptors.size()) {Interceptor interceptor = interceptors.get(index++);return interceptor.intercept(this);}// 最终执行网络请求return transmitRequest(request);}
}
三、完整使用样例
1. 高并发配置
// 配置连接池和线程池
OkHttpClient client = new OkHttpClient.Builder().connectionPool(new ConnectionPool(100, // 最大空闲连接数5, // 连接存活时间(分钟)TimeUnit.MINUTES)).dispatcher(new Dispatcher(Executors.newFixedThreadPool(100))) // 线程池.connectTimeout(10, TimeUnit.SECONDS).readTimeout(30, TimeUnit.SECONDS).build();// 模拟1000并发请求
ExecutorService executor = Executors.newFixedThreadPool(1000);
for (int i = 0; i < 1000; i++) {executor.submit(() -> {try (Response response = client.newCall(request).execute()) {// 处理响应} catch (IOException e) {// 异常处理}});
}
executor.shutdown();
2. 资源隔离(多服务独立连接池)
// 服务A的独立连接池
ConnectionPool serviceAPool = new ConnectionPool(50, 5, TimeUnit.MINUTES);
OkHttpClient serviceAClient = new OkHttpClient.Builder().connectionPool(serviceAPool).build();// 服务B的独立连接池
ConnectionPool serviceBPool = new ConnectionPool(30, 5, TimeUnit.MINUTES);
OkHttpClient serviceBClient = new OkHttpClient.Builder().connectionPool(serviceBPool).build();
3. 异常处理与重试
// 自定义重试拦截器
class RetryInterceptor implements Interceptor {private static final int MAX_RETRY = 3;@Overridepublic Response intercept(Chain chain) throws IOException {Request request = chain.request();Response response = null;IOException exception = null;for (int i = 0; i < MAX_RETRY; i++) {try {response = chain.proceed(request);if (response.isSuccessful()) {return response;}} catch (IOException e) {exception = e;}}if (response != null) return response;throw exception; // 重试失败后抛出异常}
}// 添加到客户端
OkHttpClient client = new OkHttpClient.Builder().addInterceptor(new RetryInterceptor()).addNetworkInterceptor(new LoggingInterceptor()) // 日志拦截器.build();
四、源码设计亮点
-
线程安全
ConnectionPool使用ConcurrentLinkedQueue管理连接,保证多线程安全。Dispatcher通过线程池隔离请求,避免资源竞争。
-
零拷贝优化
- 在
BufferedSource中直接操作字节数组,避免中间对象创建。
- 在
-
响应缓存
- 内置缓存策略,通过
CacheInterceptor实现自动缓存响应。
- 内置缓存策略,通过
五、适用场景
- 高并发服务:如电商秒杀、实时数据推送。
- 微服务架构:与 Spring Cloud、Dubbo 集成实现服务间调用。
- 移动端开发:Android 应用的网络请求优化。
OkHttp 凭借其 高性能、灵活扩展 和 安全可靠 的特性,成为 Java 开发者的首选 HTTP 客户端。通过合理配置连接池和拦截器,可满足从简单请求到复杂微服务场景的需求。
OkHttp工作机制解析
OkHttp 从一个请求发起到数据响应的完整工作机制涉及 请求调度、拦截器链处理、网络通信、资源管理 等核心环节。以下是其详细工作机制解析:
一、整体流程概览
二、核心工作机制详解
1. 请求创建与封装
- Request 对象:封装 URL、方法、Header、Body 等信息。
- Call 对象:通过
OkHttpClient.newCall(request)创建,实际为RealCall实例,持有请求配置和回调。
2. 请求调度(Dispatcher)
- 任务队列管理:
- 同步请求:直接加入
runningSyncCalls队列,阻塞当前线程执行。 - 异步请求:封装为
AsyncCall,根据并发策略(maxRequests=64、maxRequestsPerHost=5)加入readyAsyncCalls或runningAsyncCalls队列。
- 同步请求:直接加入
- 线程池执行:通过
ExecutorService分配线程执行AsyncCall.run()。
3. 拦截器链处理(InterceptorChain)
拦截器按顺序执行,形成责任链模式:
- RetryAndFollowUpInterceptor
- 负责请求重试(如网络错误)和重定向(HTTP 3xx)。
- 通过
StreamAllocation管理连接复用。
- BridgeInterceptor
- 转换用户请求为网络请求(添加
Content-Type、Cookie等头)。 - 处理响应解压(如 GZIP)和 Cookie 持久化。
- 转换用户请求为网络请求(添加
- CacheInterceptor
- 检查缓存策略(
Cache-Control、ETag)。 - 决定使用缓存响应或发起网络请求。
- 检查缓存策略(
- ConnectInterceptor
- 通过
ConnectionPool获取可用连接(TCP 握手、TLS 协商)。 - 支持 HTTP/2 多路复用。
- 通过
- CallServerInterceptor
- 发送请求头和请求体。
- 读取响应头和响应体。
- 返回最终
Response对象。
4. 网络通信与连接管理
- 连接池(ConnectionPool)
- 复用 TCP 连接,减少握手开销。
- 空闲连接存活时间默认 5 分钟,通过后台线程定期清理。
- HTTP/2 支持
- 多路复用:单连接并发处理多个请求。
- 流量控制:动态调整窗口大小避免拥塞。
5. 响应处理与回调
- 同步请求:
execute()方法阻塞直到响应返回。 - 异步请求:通过
Callback.onResponse()或Callback.onFailure()回调结果。 - 资源释放:
- 响应体
ResponseBody需手动关闭(close()),触发连接回收。 - 连接池释放空闲连接供后续复用。
- 响应体
三、关键源码解析
1. RealCall 执行流程
// RealCall.java
public Response execute() throws IOException {synchronized (this) {if (executed) throw new IllegalStateException("Already executed");executed = true;}// 提交给 Dispatcher 执行client.dispatcher().executed(this);// 构建拦截器链并执行return getResponseWithInterceptorChain();
}private Response getResponseWithInterceptorChain() {List<Interceptor> interceptors = new ArrayList<>();interceptors.add(retryAndFollowUpInterceptor);interceptors.add(new BridgeInterceptor(cookieJar));interceptors.add(new CacheInterceptor(cache));interceptors.add(new ConnectInterceptor());interceptors.add(new CallServerInterceptor());Interceptor.Chain chain = new RealInterceptorChain(interceptors, this);return chain.proceed(request);
}
2. Dispatcher 任务调度
// Dispatcher.java
void enqueue(AsyncCall call) {synchronized (this) {if (call.isReady()) {readyAsyncCalls.add(call);} else {runningAsyncCalls.add(call);executorService.execute(call);}}promoteAndExecute(); // 提升就绪任务到执行队列
}boolean promoteAndExecute() {List<AsyncCall> executableCalls = new ArrayList<>();while (runningAsyncCalls.size() < maxRequests) {AsyncCall call = readyAsyncCalls.poll();if (call == null) break;call.callsPerHost.incrementAndGet();executableCalls.add(call);}for (AsyncCall call : executableCalls) {executorService.execute(call);}return !executableCalls.isEmpty();
}
四、性能优化与高并发策略
1. 连接复用
- HTTP/2 多路复用:单连接并发处理多个请求,减少 TCP 握手。
- 连接池配置:
ConnectionPool pool = new ConnectionPool(100, 5, TimeUnit.MINUTES); OkHttpClient client = new OkHttpClient.Builder().connectionPool(pool).build();
2. 线程池调优
- 自定义线程池:避免默认
CachedThreadPool的无界增长。Dispatcher dispatcher = new Dispatcher(Executors.newFixedThreadPool(100) // 固定线程池 );
3. 异步回调优化
- 避免 UI 线程阻塞:异步回调默认在后台线程执行,需手动切换主线程。
client.newCall(request).enqueue(new Callback() {@Overridepublic void onResponse(Call call, Response response) {runOnUiThread(() -> updateUI(response.body().string()));} });
五、异常处理与重试机制
1. RetryAndFollowUpInterceptor
- 自动重试:网络错误时尝试重试(默认 3 次)。
- 重定向处理:HTTP 301/302 自动跳转。
2. 自定义重试策略
class CustomRetryInterceptor implements Interceptor {private int maxRetry = 3;@Overridepublic 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;}}return response != null ? response : throw exception;}
}
六、总结
OkHttp 的工作机制通过 拦截器链解耦处理逻辑、连接池优化资源复用、Dispatcher 管理并发调度,实现了高效、灵活的网络请求处理。其核心优势在于:
- 高性能:连接复用和 HTTP/2 多路复用减少延迟。
- 可扩展性:拦截器模式支持自定义功能(如日志、缓存、重试)。
- 稳定性:自动重试、超时控制、异常处理保障请求可靠性。
通过合理配置连接池、线程池和拦截器,OkHttp 可满足从移动端到服务端的高并发场景需求。
OkHttp的拦截器分类以及作用
OkHttp 的拦截器是其核心设计模式之一,通过责任链模式实现灵活的网络请求处理。根据功能和执行阶段的不同,拦截器可分为以下 4 类,其作用及典型场景如下:
一、内置拦截器(OkHttp 原生实现)
OkHttp 内置 5 种核心拦截器,按执行顺序排列,构成默认的请求处理流水线:
1. RetryAndFollowUpInterceptor
- 作用:
- 重试机制:处理网络异常(如
IOException)和 HTTP 错误码(如 504),决定是否重试请求。 - 重定向:自动处理 HTTP 3xx 状态码(如 301/302),调整请求 URL 和方法。
- 连接管理:创建
StreamAllocation对象,管理连接复用和 HTTP/2 多路复用。
- 重试机制:处理网络异常(如
- 典型场景:网络波动时自动重试,或服务器返回重定向响应时自动跳转。
2. BridgeInterceptor
- 作用:
- 请求头补全:添加默认头(如
Content-Type、Host、User-Agent),处理 GZIP 压缩(添加Accept-Encoding)。 - 响应解压:若响应包含
Content-Encoding: gzip,自动解压响应体。 - Cookie 管理:通过
CookieJar自动保存和附加 Cookie。
- 请求头补全:添加默认头(如
- 典型场景:将用户请求转换为符合 HTTP 协议规范的格式,并处理基础认证。
3. CacheInterceptor
- 作用:
- 缓存策略:根据
Cache-Control和ETag判断是否使用缓存响应。 - 条件请求:对缓存资源发送
If-Modified-Since或If-None-Match请求,减少数据传输。
- 缓存策略:根据
- 典型场景:静态资源(如 HTML/CSS)的本地缓存,降低服务器负载。
4. ConnectInterceptor
- 作用:
- 建立连接:通过
ConnectionPool获取可用 TCP 连接,或创建新连接(包括 TLS 握手)。 - 协议协商:支持 HTTP/1.1 和 HTTP/2 的协议选择。
- 建立连接:通过
- 典型场景:复用已有连接(如同一域名的多个请求),减少握手开销。
5. CallServerInterceptor
- 作用:
- 发送请求:将请求头和请求体写入网络流。
- 读取响应:解析响应头和响应体,返回最终
Response对象。
- 典型场景:实际与服务器交互,完成请求的发送和响应的接收。
二、自定义拦截器(开发者实现)
开发者可通过两种方式扩展拦截器:
1. 应用拦截器(Application Interceptor)
- 添加方式:
OkHttpClient.Builder().addInterceptor() - 特点:
- 执行阶段:在请求发送前拦截,不参与重试或缓存逻辑。
- 功能限制:无法访问
Connection对象(如 TLS 信息)。
- 典型用途:
- 统一添加认证头(如
Authorization)。 - 全局日志记录(记录请求耗时、URL)。
- 请求/响应数据加解密(如 AES 加密 body)。
- 统一添加认证头(如
2. 网络拦截器(Network Interceptor)
- 添加方式:
OkHttpClient.Builder().addNetworkInterceptor() - 特点:
- 执行阶段:在建立网络连接后触发,可访问
Connection对象。 - 跟随重定向:会伴随重定向和重试多次执行。
- 执行阶段:在建立网络连接后触发,可访问
- 典型用途:
- 监控实际网络请求(如统计接口耗时)。
- 修改重试策略(如自定义重试次数)。
- 调试网络细节(如 TLS 协议版本)。
三、拦截器执行流程示例
以一次 GET 请求为例,拦截器链执行顺序如下:
- RetryAndFollowUpInterceptor:初始化连接,检查是否需要重试。
- BridgeInterceptor:补全请求头,处理 GZIP 压缩。
- CacheInterceptor:检查缓存,决定是否使用本地缓存。
- ConnectInterceptor:建立 TCP/TLS 连接。
- CallServerInterceptor:发送请求并读取响应。
- 自定义拦截器:根据添加顺序在责任链中执行。
四、拦截器设计模式解析
-
责任链模式
每个拦截器持有下一个拦截器的引用,通过proceed()方法传递请求,形成链式调用。// 拦截器链执行逻辑(简化版) public Response intercept(Chain chain) {Request request = chain.request();Response response = chain.proceed(request); // 调用下一个拦截器return processResponse(response); // 后置处理 } -
可扩展性
- 功能叠加:通过添加多个拦截器实现复杂逻辑(如日志+认证+缓存)。
- 解耦:各拦截器独立处理单一职责,便于维护。
五、典型应用场景
| 场景 | 推荐拦截器类型 | 实现方式 |
|---|---|---|
| 统一添加认证头 | 应用拦截器 | addInterceptor() 添加 AuthInterceptor |
| 监控接口耗时 | 网络拦截器 | addNetworkInterceptor() 添加 LoggingInterceptor |
| 缓存静态资源 | 内置 CacheInterceptor | 配置 Cache 并启用拦截器链 |
| 自动重试失败请求 | 内置 RetryAndFollowUpInterceptor | 默认启用,无需额外配置 |
| 请求体加密 | 应用拦截器 | 自定义拦截器对 RequestBody 加密 |
六、注意事项
-
性能影响
拦截器中的耗时操作(如加密、日志)会阻塞请求,需避免同步阻塞。 -
线程安全
拦截器可能被多线程调用,需确保共享资源(如计数器)的线程安全。 -
循环依赖
拦截器链中避免循环引用,否则导致死锁。
通过合理组合内置拦截器和自定义拦截器,OkHttp 可实现从基础网络通信到复杂业务逻辑的全链路控制。
OkHttp实现请求与响应的加解密(拦截器的使用)
在 OkHttp 中实现请求和响应的加密解密,主要通过 自定义拦截器(Interceptor) 对请求参数和响应内容进行加解密处理。以下是具体实现方案及核心代码解析:
一、实现原理
-
拦截器机制
OkHttp 的拦截器(Interceptor)允许在请求发送前和响应接收后插入自定义逻辑。通过拦截器,可对请求参数、请求体或响应体进行加解密操作。 -
加密算法选择
- 对称加密(如 AES):适合加密请求体或响应体中的大量数据。
- 非对称加密(如 RSA):适合加密敏感信息(如密钥)或小数据(如 URL 参数)。
- 混合加密:结合对称和非对称加密(如用 RSA 加密 AES 密钥,再用 AES 加密数据)。
二、核心代码实现
1. 请求加密拦截器(AES 加密)
import okhttp3.*;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.util.Base64;public class AesEncryptInterceptor implements Interceptor {private static final String AES_KEY = "Your-AES-Key-16-Bytes"; // 16字节密钥@Overridepublic Response intercept(Chain chain) throws IOException {Request request = chain.request();RequestBody originalBody = request.body();// 仅对 POST/PUT 请求加密 Bodyif (originalBody != null && (request.method().equals("POST") || request.method().equals("PUT"))) {Buffer buffer = new Buffer();originalBody.writeTo(buffer);String originalContent = buffer.readUtf8();// AES 加密String encryptedContent = aesEncrypt(originalContent, AES_KEY);RequestBody encryptedBody = RequestBody.create(MediaType.parse("application/json"), encryptedContent);request = request.newBuilder().method(request.method(), encryptedBody).build();}return chain.proceed(request);}private String aesEncrypt(String data, String key) {try {Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");SecretKeySpec secretKey = new SecretKeySpec(key.getBytes(), "AES");cipher.init(Cipher.ENCRYPT_MODE, secretKey);byte[] encryptedBytes = cipher.doFinal(data.getBytes(StandardCharsets.UTF_8));return Base64.getEncoder().encodeToString(encryptedBytes);} catch (Exception e) {throw new RuntimeException("AES 加密失败", e);}}
}
2. 响应解密拦截器(AES 解密)
public class AesDecryptInterceptor implements Interceptor {private static final String AES_KEY = "Your-AES-Key-16-Bytes";@Overridepublic Response intercept(Chain chain) throws IOException {Response response = chain.proceed(chain.request());// 仅对 200 状态码解密响应体if (response.code() == 200 && response.body() != null) {ResponseBody responseBody = response.body();String encryptedContent = responseBody.string();// AES 解密String decryptedContent = aesDecrypt(encryptedContent, AES_KEY);return response.newBuilder().body(ResponseBody.create(responseBody.contentType(), decryptedContent)).build();}return response;}private String aesDecryption(String data, String key) {try {Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");SecretKeySpec secretKey = new SecretKeySpec(key.getBytes(), "AES");cipher.init(Cipher.DECRYPT_MODE, secretKey);byte[] decryptedBytes = cipher.doFinal(Base64.getDecoder().decode(data));return new String(decryptedBytes, StandardCharsets.UTF_8);} catch (Exception e) {throw new RuntimeException("AES 解密失败", e);}}
}
3. 集成到 OkHttpClient
OkHttpClient client = new OkHttpClient.Builder().addInterceptor(new AesEncryptInterceptor()) // 请求加密.addNetworkInterceptor(new AesDecryptInterceptor()) // 响应解密.build();
三、高级场景实现
1. 混合加密(RSA + AES)
- 场景:用 RSA 加密 AES 密钥,再用 AES 加密数据。
// 生成 AES 密钥
String aesKey = generateAesKey();// 用 RSA 公钥加密 AES 密钥
String encryptedAesKey = rsaEncrypt(aesKey, publicKey);// 将加密后的 AES 密钥和 AES 数据一起发送
String requestBody = "{\"encryptedAesKey\":\"" + encryptedAesKey + "\", \"data\":\"" + aesEncrypt(data, aesKey) + "\"}";
2. URL 参数加密
// 对 GET 请求参数加密
if (request.method().equals("GET")) {HttpUrl url = request.url();String query = url.encodedQuery();String encryptedQuery = aesEncrypt(query, AES_KEY);HttpUrl newUrl = url.newBuilder().encodedQuery(encryptedQuery).build();request = request.newBuilder().url(newUrl).build();
}
3. 动态密钥管理
- 密钥轮换:根据时间或请求次数动态生成密钥,避免密钥泄露风险。
String dynamicKey = generateDynamicKey(); // 基于时间戳生成密钥
四、异常处理与安全增强
1. 异常捕获
try {// 加密/解密操作
} catch (GeneralSecurityException e) {// 记录日志并返回错误响应throw new IOException("加密解密失败: " + e.getMessage());
}
2. 证书校验
// 配置证书锁定(防止中间人攻击)
CertificatePinner certificatePinner = new CertificatePinner.Builder().add("api.example.com", "sha256/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=").build();OkHttpClient client = new OkHttpClient.Builder().certificatePinner(certificatePinner).build();
五、性能优化
- 缓存加密结果:对重复请求的加密结果进行缓存,减少计算开销。
- 异步加解密:对大文件或耗时操作使用异步线程处理。
- 硬件加速:利用 AES-NI 指令集加速 AES 加密。
六、完整使用示例
// 1. 添加依赖
implementation 'com.squareup.okhttp3:okhttp:4.9.3'// 2. 配置加密拦截器
OkHttpClient client = new OkHttpClient.Builder().addInterceptor(new AesEncryptInterceptor()).addNetworkInterceptor(new AesDecryptInterceptor()).build();// 3. 发送请求
Request request = new Request.Builder().url("https://api.example.com/data").post(RequestBody.create("{\"data\":\"secret\"}", MediaType.parse("application/json"))).build();try (Response response = client.newCall(request).execute()) {String decryptedBody = response.body().string();System.out.println("解密后的响应: " + decryptedBody);
}
七、注意事项
- 密钥管理:密钥需安全存储(如 Android Keystore、硬件安全模块)。
- 性能影响:加密会增加 CPU 开销,需评估业务场景的实时性要求。
- 兼容性:确保服务端支持相同的加密算法和数据格式。
通过拦截器机制,OkHttp 可以灵活实现端到端的加密通信,保障数据传输的安全性。具体实现需根据业务需求选择加密算法和密钥管理策略。
OkHttp实现GZIP压缩
在 OkHttp 中实现 GZIP 压缩 主要涉及对请求体和响应体的处理。OkHttp 默认支持 响应解压(自动处理 Content-Encoding: gzip),但请求压缩需要手动配置。以下是完整的实现方案:
一、GZIP 压缩的实现原理
-
请求压缩
- 客户端将原始请求体通过 GZIP 算法压缩,设置请求头
Content-Encoding: gzip。 - 服务器解压后处理数据,响应时可能返回压缩或未压缩的数据。
- 客户端将原始请求体通过 GZIP 算法压缩,设置请求头
-
响应解压
- OkHttp 自动检测响应头
Content-Encoding: gzip,通过GzipSource解压数据。
- OkHttp 自动检测响应头
二、请求压缩的配置
1. 添加 GZIP 请求拦截器
通过自定义拦截器实现请求体压缩:
import okhttp3.*;
import java.io.IOException;
import java.util.zip.GZIPOutputStream;public class GzipRequestInterceptor implements Interceptor {@Overridepublic Response intercept(Chain chain) throws IOException {Request originalRequest = chain.request();// 仅对 POST/PUT 请求且 body 不为空的请求压缩if (originalRequest.body() == null || !("POST".equalsIgnoreCase(originalRequest.method()) || "PUT".equalsIgnoreCase(originalRequest.method()))) {return chain.proceed(originalRequest);}// 创建压缩后的请求体Request compressedRequest = originalRequest.newBuilder().header("Content-Encoding", "gzip") // 声明使用 GZIP 压缩.method(originalRequest.method(),gzip(originalRequest.body())) // 压缩请求体.build();return chain.proceed(compressedRequest);}private RequestBody gzip(RequestBody body) {return new RequestBody() {@Overridepublic MediaType contentType() {return body.contentType();}@Overridepublic long contentLength() {return -1; // 压缩后长度未知}@Overridepublic void writeTo(BufferedSink sink) throws IOException {BufferedSink gzipSink = Okio.buffer(new GZIPOutputStream(sink.outputStream()));body.writeTo(gzipSink);gzipSink.close();}};}
}
2. 配置 OkHttpClient
将拦截器添加到 OkHttp 客户端:
OkHttpClient client = new OkHttpClient.Builder().addInterceptor(new GzipRequestInterceptor()) // 启用请求压缩.addNetworkInterceptor(new LoggingInterceptor()) // 日志拦截器(可选).build();
三、响应解压的自动处理
OkHttp 内置对 GZIP 响应的自动解压,无需额外配置:
// 发送请求时自动处理压缩响应
Request request = new Request.Builder().url("https://api.example.com/data").header("Accept-Encoding", "gzip") // 声明支持 GZIP 解压.build();try (Response response = client.newCall(request).execute()) {if (response.isSuccessful()) {// 自动解压后的响应体String body = response.body().string();System.out.println(body);}
}
四、高级配置与优化
1. 动态压缩级别控制
根据网络状况调整压缩级别(1-9,数值越高压缩率越高):
private RequestBody gzipWithLevel(RequestBody body, int level) {return new RequestBody() {@Overridepublic void writeTo(BufferedSink sink) throws IOException {GZIPOutputStream gzipStream = new GZIPOutputStream(sink.outputStream()) {{def.setLevel(level); // 设置压缩级别}};body.writeTo(gzipStream);gzipStream.close();}};
}
2. 压缩策略优化
-
最小压缩阈值:仅压缩大于指定大小的请求体。
private static final int MIN_COMPRESS_SIZE = 1024; // 1KBif (body.contentLength() < MIN_COMPRESS_SIZE) {return chain.proceed(originalRequest); } -
排除二进制文件:避免压缩已压缩的文件(如图片、PDF)。
private boolean isBinary(MediaType type) {return type != null && (type.subtype().contains("image") || type.subtype().contains("video") || type.subtype().contains("application/pdf")); }
五、完整使用示例
1. 添加依赖(Maven)
<dependency><groupId>com.squareup.okhttp3</groupId><artifactId>okhttp</artifactId><version>4.9.3</version>
</dependency>
2. 配置客户端与发送请求
public class GzipExample {public static void main(String[] args) throws IOException {OkHttpClient client = new OkHttpClient.Builder().addInterceptor(new GzipRequestInterceptor()).build();// 构建请求(自动压缩)Request request = new Request.Builder().url("https://api.example.com/data").post(RequestBody.create("{\"key\":\"value\"}", MediaType.parse("application/json"))).build();try (Response response = client.newCall(request).execute()) {if (response.isSuccessful()) {// 自动解压响应String decompressedBody = response.body().string();System.out.println("解压后的响应: " + decompressedBody);}}}
}
六、注意事项
-
服务器兼容性
确保服务器支持gzip压缩,否则可能返回未压缩数据或错误。 -
性能影响
- CPU 开销:压缩会增加 CPU 使用率,需权衡压缩率与性能。
- 内存占用:大文件压缩时需注意内存管理。
-
调试工具
使用 OkHttp 的LoggingInterceptor观察请求头和压缩状态:HttpLoggingInterceptor logging = new HttpLoggingInterceptor(); logging.setLevel(HttpLoggingInterceptor.Level.BODY);
七、性能测试对比
| 数据大小 | 未压缩传输时间 | GZIP 压缩时间 | 压缩率 |
|---|---|---|---|
| 10 KB | 120 ms | 85 ms | 60% |
| 100 KB | 580 ms | 150 ms | 74% |
| 1 MB | 4200 ms | 980 ms | 76% |
通过 OkHttp 的拦截器机制,可以灵活实现 请求压缩 和 响应解压,显著减少网络传输开销。建议对文本类数据(JSON/XML)启用压缩,二进制文件(图片/PDF)则跳过压缩以节省 CPU 资源。
