OkHttp 是 Square 公司开发的一个高效、功能强大的 HTTP 客户端库,因其简洁的 API、灵活的拦截器链、内置连接池、透明 GZIP 压缩、响应缓存以及对 HTTP/2 和 WebSocket 的支持,已成为 Android 和 Java 应用开发中 事实上的标准 网络库。
// 1. 创建 OkHttpClient 实例 (通常全局共享一个实例)
OkHttpClient client = new OkHttpClient.Builder()
.connectTimeout(10, TimeUnit.SECONDS) // 连接超时
.readTimeout(30, TimeUnit.SECONDS) // 读取超时
.writeTimeout(30, TimeUnit.SECONDS) // 写入超时
.cache(new Cache(context.getCacheDir(), 10 * 1024 * 1024)) // 10MB 缓存
.build();
// 2. 构建请求 (Request)
Request request = new Request.Builder()
.url("https://api.example.com/data")
.header("Authorization", "Bearer token123") // 添加请求头
.post(RequestBody.create(MediaType.get("application/json"), jsonData)) // POST 请求体
.build();
// 3. 发起请求 (同步)
try (Response response = client.newCall(request).execute()) {
if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);
String responseBody = response.body().string(); // 获取响应体字符串
// 处理 responseBody...
}
// 3. 发起请求 (异步)
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 body = response.body()) {
if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);
String responseData = body.string();
// 切换到主线程更新 UI...
}
}
});
OkHttpClient
: 核心入口点。封装了连接池、线程池、缓存、拦截器链等配置。最佳实践是全局共享一个实例(单例模式),以最大化利用连接池和线程池资源。Request
: 封装 HTTP 请求信息(URL、方法、Headers、Body)。Call
: 代表一个已准备就绪可以执行的请求。由 OkHttpClient.newCall(Request)
创建。每个 Call
实例只能执行一次。Response
: 封装 HTTP 响应信息(状态码、Headers、Body)。ResponseBody
: 封装响应体数据流。必须关闭(close()
或 try-with-resources)以避免资源泄漏。可通过 string()
, bytes()
, charStream()
, byteStream()
, source()
等方法读取内容。拦截器 Interceptor
:
// 日志拦截器示例
public 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 on %s%n%s",
request.url(), chain.connection(), request.headers()));
Response response = chain.proceed(request); // 关键:将请求传递给下一个拦截器或网络
long endTime = System.nanoTime();
Log.d("OkHttp", String.format("Received response for %s in %.1fms%n%s",
response.request().url(), (endTime - startTime) / 1e6d, response.headers()));
return response;
}
}
// 添加到 OkHttpClient
OkHttpClient client = new OkHttpClient.Builder()
.addInterceptor(new LoggingInterceptor())
.build();
addInterceptor(Interceptor)
: 应用拦截器,最先执行,最后获得响应。通常用于与请求/响应内容无关的操作(如日志、添加通用 Header)。addNetworkInterceptor(Interceptor)
: 网络拦截器,在连接建立后、实际网络传输前后执行。可以访问到承载请求的 Connection
对象。通常用于与网络传输相关的操作(如重定向、重试)。连接池 ConnectionPool
:
ConnectionPool
),复用 HTTP/1.x 连接和 HTTP/2/3 的多路复用连接,显著减少 TCP 握手和 TLS 握手的开销。OkHttpClient.Builder.connectionPool(new ConnectionPool(maxIdleConnections, keepAliveDuration, timeUnit))
可自定义。缓存 Cache
:
Cache-Control
, ETag
, Last-Modified
等)。OkHttpClient.Builder.cache(new Cache(directory, maxSize))
启用。超时控制:
connectTimeout
: 建立 TCP 连接或 TLS 握手的超时。readTimeout
: 从服务器读取数据的超时(两次数据包到达间隔)。writeTimeout
: 向服务器写入数据的超时(两次数据包发送间隔)。callTimeout
: 整个请求从开始到完成的超时(包含重定向/重试)。Cookie 管理:
OkHttpClient.Builder.cookieJar(CookieJar)
接口实现。PersistentCookieJar
(如 okhttp3:okhttp-urlconnection
或第三方库)。认证 Authenticator
:
401 Unauthorized
和 407 Proxy Authentication Required
响应。OkHttpClient.Builder.authenticator(Authenticator)
和 .proxyAuthenticator(Authenticator)
设置。WebSocket:
WebSocket
API 用于双向通信。Request request = new Request.Builder().url("wss://echo.websocket.org").build();
WebSocketListener listener = new WebSocketListener() { /* 实现回调方法 */ };
WebSocket webSocket = client.newWebSocket(request, listener);
webSocket.send("Hello!"); // 发送消息
webSocket.close(1000, "Goodbye!"); // 正常关闭
HTTPS / SSL Pinning:
OkHttpClient.Builder.sslSocketFactory(SSLSocketFactory, X509TrustManager)
自定义信任策略。CertificatePinner pinner = new CertificatePinner.Builder()
.add("api.example.com", "sha256/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=")
.build();
OkHttpClient client = new OkHttpClient.Builder()
.certificatePinner(pinner)
.build();
OkHttp 的卓越性能和高可靠性源于其精心设计的内部架构和核心组件:
Interceptor.Chain
)chain.proceed(request)
) 将请求依次传递下去,最终到达网络层,再将响应依次返回。addInterceptor
):用户自定义,最先执行请求处理,最后执行响应处理。通常用于全局逻辑(日志、添加头、修改请求体)。RetryAndFollowUpInterceptor
:处理重定向 (3xx 响应) 和可恢复的失败请求重试(如连接失败、路由失败)。BridgeInterceptor
:桥接用户请求和网络请求。添加必要的默认 Headers(如 Host
, User-Agent
, Connection
, Content-Type
, Content-Length
, Accept-Encoding
),处理 GZIP 压缩(自动解压 Content-Encoding: gzip
响应体),处理 Cookie(如果有 CookieJar
)。CacheInterceptor
:处理 HTTP 缓存。根据请求和缓存策略决定是否使用缓存响应。可能发送条件请求 (If-Modified-Since
, If-None-Match
) 验证缓存有效性。将符合条件的响应写入缓存。ConnectInterceptor
:关键环节。负责建立到目标服务器的实际网络连接(TCP 或 TLS)。它会从连接池 (ConnectionPool
) 中查找可复用的连接,如果找不到则创建新连接。最终得到一个 Exchange
对象,它封装了底层的连接和用于读写数据的流。addNetworkInterceptor
):在连接建立后、实际网络传输前执行。可以访问到承载请求的 Connection
对象。通常用于网络层监控、修改网络请求。CallServerInterceptor
:最终执行网络 I/O。使用 Exchange
中的流将请求的 Headers 和 Body 写入网络。读取响应的状态行、Headers 和 Body。这是网络操作实际发生的地方。ConnectionPool
, RealConnection
)ConnectionPool
:
RealConnection
(物理连接)。Executor
),定期扫描并关闭空闲时间超过 keepAliveDuration
的连接或超过 maxIdleConnections
数量的多余连接。Deque
存储空闲连接(按最近使用时间排序)。RealConnection
:
Socket
(TCP)或 SSLSocket
(TLS)连接。Route
)、创建时间、最后使用时间。Http2Connection
对象管理多路复用的流 (Stream
)。ConnectInterceptor
):
ConnectionPool
获取一个可复用的连接 (address
, route
匹配,连接可用且未关闭)。RouteSelector
选择的路由 (Route
),创建一个新的 RealConnection
。Socket.connect()
)。https
),执行 TLS 握手 (SSLSocket.startHandshake()
)。connectionPreface
)。Exchange
。RouteSelector
, Route
)Route
: 表示一个具体的网络路径,包含:目标地址 (Address
- IP 地址或域名、端口、协议)、使用的代理 (Proxy
)、连接使用的具体 IP 地址(通过 DNS 查询获得)。RouteSelector
:
Route
。Proxy
配置(直接、系统代理、指定代理)确定代理类型。InetAddress.getAllByName()
,可通过 OkHttpClient.Builder.dns(Dns)
自定义)。Route
组合(代理 + IP 地址)。IOException
)或需要重试时,RouteSelector
会尝试下一个可用的 Route
(连接失败自动切换 IP 的原理)。Exchange
, ExchangeCodec
)Exchange
: 在 ConnectInterceptor
中创建,绑定到一个特定的 RealConnection
。封装了一次 HTTP 交互的上下文(请求计数、事件监听)。ExchangeCodec
:
Http1ExchangeCodec
: 处理 HTTP/1.1 请求。管理 Socket
的输入/输出流 (Source
/Sink
)。Http2ExchangeCodec
: 处理 HTTP/2 请求。通过 Http2Connection
创建新的 Stream
(Http2Stream
),并通过流的 Source
/Sink
读写数据。CallServerInterceptor
通过 Exchange
获取 ExchangeCodec
来实际读写网络数据。Dispatcher
:
readyAsyncCalls
: 等待执行的异步请求队列。runningAsyncCalls
: 正在执行的异步请求队列(包括正在寻找可用连接的请求)。runningSyncCalls
: 正在执行的同步请求队列(较少用,因为同步请求通常由调用者线程管理)。ExecutorService
) 执行异步请求的网络操作。默认线程池配置根据需求动态调整线程数(类似 CachedThreadPool
)。setMaxRequests(int max)
: 最大并发请求数(默认 64)。setMaxRequestsPerHost(int max)
: 单个主机最大并发请求数(默认 5)。这对避免对单个服务器造成过大压力很重要。Dispatcher
会从 readyAsyncCalls
中取出等待的请求放入线程池执行。Stream
)。消除了 HTTP/1.1 的队头阻塞 (Head-of-Line Blocking - 慢请求阻塞后续请求),极大提高并发性能。HEADERS
, DATA
, PRIORITY
, RST_STREAM
, SETTINGS
, PUSH_PROMISE
, PING
, GOAWAY
),并高效编码传输。帧可以交错发送和接收。PushObserver
处理推送。OkHttp 通过以下机制实现高效可靠:
Dispatcher
):管理并发请求。理解这些底层原理对于高效使用 OkHttp、诊断网络问题、进行高级定制(如自定义拦截器、连接池调优、DNS 策略)至关重要。OkHttp 的设计充分体现了关注点分离和性能优化的思想。