Skip to content

08_OkHttp 底层

目录


OkHttp 概述

1.1 什么是 OkHttp

OkHttp 是 Square 公司开源的 HTTP 客户端库,由 Java 和 Kotlin 编写,支持 Android 和 Java 平台。它已成为 Android 网络请求的事实标准。

核心特性

  • 高性能的 HTTP 客户端
  • 支持 HTTP/1.1、HTTP/2、HTTP/3
  • 内置连接池
  • 支持拦截器
  • 支持 WebSocket
  • 自动重试和重定向
  • 完善的缓存机制

1.2 发展历程

2011 年:OkHttp 1.0 发布
2015 年:OkHttp 3.0 支持 HTTP/2
2017 年:OkHttp 4.0 支持 Kotlin 协程
2020 年:OkHttp 4.9+ 持续优化
2024 年:OkHttp 5.0 支持 HTTP/3

1.3 为什么选择 OkHttp

对比 HttpClient

HttpClient:
- 老牌库,已过时
- 无 HTTP/2 支持
- 性能较差
- API 复杂

OkHttp:
- 活跃维护
- HTTP/2 原生支持
- 性能优异
- API 简洁

对比 Volley

Volley:
- Google 开发,不再维护
- 队列管理
- 缓存机制

OkHttp:
- Square 开发,活跃维护
- 连接池
- 拦截器机制

OkHttp 架构

2.1 整体架构

┌────────────────────────────────────┐
│         应用层                      │
│   Call / CallAdapter               │
└───────────┬────────────────────────┘

┌───────────▼────────────────────────┐
│        Dispatcher                  │
│    (调度器,管理异步请求)           │
└───────────┬────────────────────────┘

┌───────────▼────────────────────────┐
│        OkHttpClient                │
│      (配置和拦截器链)               │
└───────────┬────────────────────────┘

┌───────────▼────────────────────────┐
│        Interceptor Chain           │
│      (拦截器链)                    │
├─────────────────────────────────────┤
│  - Application Interceptors         │
│  - RetryAndFollowUpInterceptor      │
│  - BridgeInterceptor               │
│  - CacheInterceptor                │
│  - ConnectInterceptor              │
│  - Network Interceptors            │
└───────────┬────────────────────────┘

┌───────────▼────────────────────────┐
│        ConnectionPool              │
│      (连接池管理)                  │
└───────────┬────────────────────────┘

┌───────────▼────────────────────────┐
│        HttpCodec                   │
│    (HTTP 编码解码)                 │
│  - Http1Codec                      │
│  - Http2Codec                      │
└───────────┬────────────────────────┘

┌───────────▼────────────────────────┐
│        Socket                      │
│      (TCP/HTTP/2 连接)              │
└────────────────────────────────────┘

2.2 核心组件

OkHttpClient

kotlin
class OkHttpClient {
    // 拦截器
    private val applicationInterceptors: List<Interceptor>
    private val networkInterceptors: List<Interceptor>
    
    // 连接池
    private val connectionPool: ConnectionPool
    
    // 缓存
    private val cache: Cache?
    
    // 调度器
    private val dispatcher: Dispatcher
    
    // 超时配置
    private val connectTimeout: Duration
    private val readTimeout: Duration
    private val writeTimeout: Duration
    
    // 协议支持
    private val protocols: List<Protocol>
    
    // DNS
    private val dns: Dns
}

Call

kotlin
interface Call {
    fun execute(): Response
    fun enqueue(callback: Callback)
    fun cancel()
    fun isExecuted(): Boolean
    fun isCanceled(): Boolean
    fun request(): Request
}

// RealCall:实际的调用实现
class RealCall(
    val client: OkHttpClient,
    val originalRequest: Request
) : Call {
    // 执行请求
}

Dispatcher

kotlin
class Dispatcher {
    // 正在执行的异步请求队列
    private val runningAsyncCalls: SynchronousQueue<ExecutableCall>
    
    // 等待执行的异步请求队列
    private val readyAsyncCalls: PriorityDeque<ExecutableCall>
    
    // 正在执行的同步请求队列
    private val runningSyncCalls: SynchronousQueue<ExecutableCall>
    
    // 等待执行的同步请求队列
    private val readySyncCalls: PriorityDeque<ExecutableCall>
    
    // 最大并发数
    private var maxRequests: Int = 64
    private var maxRequestsPerHost: Int = 5
    
    // 线程池
    private val executorService: ExecutorService
}

2.3 请求流程

完整的请求流程

1. 创建 Request
2. 创建 Call(RealCall)
3. 添加到 Dispatcher 队列
4. 执行拦截器链
5. 获取连接(从连接池或新建)
6. 发送请求
7. 接收响应
8. 拦截器链返回
9. 回调结果

流程图

用户代码


Request + OkHttpClient


RealCall


Dispatcher(异步时)


拦截器链开始

   ├─ Application Interceptor #1
   ├─ Application Interceptor #2
   ├─ RetryAndFollowUpInterceptor
   ├─ BridgeInterceptor
   ├─ CacheInterceptor
   ├─ ConnectInterceptor
   ├─ Network Interceptor #1
   ├─ Network Interceptor #2


Socket 通信


响应处理(反向)


回调结果

拦截器链

3.1 拦截器类型

两种拦截器

  1. 应用拦截器(Application Interceptor)
kotlin
// 拦截所有请求(包括缓存)
client.addInterceptor(loggingInterceptor)
  1. 网络拦截器(Network Interceptor)
kotlin
// 只拦截实际网络请求
client.addNetworkInterceptor(retryInterceptor)

3.2 拦截器执行顺序

完整的执行顺序

┌─────────────────────────────────────┐
│ 1. Application Interceptor #1       │
│    - 记录日志                       │
│    - 添加通用 Header                 │
├─────────────────────────────────────┤
│ 2. Application Interceptor #2       │
│    - Token 刷新                     │
│    - 请求重试                       │
├─────────────────────────────────────┤
│ 3. RetryAndFollowUpInterceptor      │
│    - 自动重试                       │
│    - 处理重定向                     │
├─────────────────────────────────────┤
│ 4. BridgeInterceptor               │
│    - 处理 Cookie                    │
│    - 处理 Content-Length            │
│    - 处理 Accept-Encoding           │
├─────────────────────────────────────┤
│ 5. CacheInterceptor                │
│    - 检查缓存                       │
│    - 返回缓存或继续                 │
├─────────────────────────────────────┤
│ 6. ConnectInterceptor              │
│    - 获取连接                       │
│    - 建立 TCP/TLS 连接               │
├─────────────────────────────────────┤
│ 7. Network Interceptor #1           │
│    - 添加网络相关 Header            │
├─────────────────────────────────────┤
│ 8. Network Interceptor #2           │
│    - 记录网络耗时                   │
├─────────────────────────────────────┤
│ 9. RealCall.blackBoxInterceptor    │
│    - SSL Pinning                    │
└─────────────────────────────────────┘


    Socket 通信

响应返回顺序(反向):

Socket 响应


9 <- 8 <- 7 <- 6 <- 5 <- 4 <- 3 <- 2 <- 1

3.3 内置拦截器详解

RetryAndFollowUpInterceptor

kotlin
class RetryAndFollowUpInterceptor : Interceptor {
    override fun intercept(chain: Interceptor.Chain): Response {
        var request = chain.request()
        var response: Response?
        
        // 重试循环
        for (i in 0 until retryCount + 1) {
            try {
                response = chain.proceed(request)
                
                // 处理重定向
                if (response.code == 301 || response.code == 302) {
                    val location = response.header("Location")
                    request = request.newBuilder()
                        .url(location)
                        .build()
                    continue
                }
                
                return response
            } catch (e: IOException) {
                // 可重试的错误
                if (isRetryable(e)) {
                    continue
                }
                throw e
            }
        }
        
        throw IOException("Failed after $retryCount retries")
    }
}

BridgeInterceptor

kotlin
class BridgeInterceptor : Interceptor {
    override fun intercept(chain: Interceptor.Chain): Response {
        var request = chain.request()
        
        // 处理 Cookie
        val cookieHeader = request.header("Cookie")
        if (cookieHeader != null) {
            request = request.newBuilder()
                .header("Cookie", cookieHeader)
                .build()
        }
        
        // 处理 Content-Length
        if (request.body != null && request.header("Content-Length") == null) {
            request = request.newBuilder()
                .header("Content-Length", request.body!!.contentLength().toString())
                .build()
        }
        
        // 处理 Accept-Encoding
        if (request.header("Accept-Encoding") == null) {
            request = request.newBuilder()
                .header("Accept-Encoding", "gzip")
                .build()
        }
        
        val response = chain.proceed(request)
        
        // 处理响应 Cookie
        // ...
        
        return response
    }
}

CacheInterceptor

kotlin
class CacheInterceptor : Interceptor {
    private val cache: Cache
    
    override fun intercept(chain: Interceptor.Chain): Response {
        val request = chain.request()
        
        // 检查是否只使用缓存
        val onlyIfCached = request.cacheControl.onlyIfCached()
        if (onlyIfCached && cache == null) {
            return noCacheResponse(request)
        }
        
        // 从缓存获取
        val cacheResponse = cache.get(request)
        
        // 缓存命中且有效
        if (cacheResponse != null && isCacheValid(cacheResponse, request)) {
            return cacheResponse
        }
        
        // 网络请求
        val networkResponse = chain.proceed(request)
        
        // 写入缓存
        if (canCache(networkResponse, request)) {
            cache.write(request, networkResponse)
        }
        
        return networkResponse
    }
}

ConnectInterceptor

kotlin
class ConnectInterceptor : Interceptor {
    override fun intercept(chain: Interceptor.Chain): Response {
        val realChain = chain as RealInterceptorChain
        val address = realChain.address()
        var connection = realChain.connection()
        
        // 如果没有连接,建立新连接
        if (connection == null) {
            connection = realChain.connectionPool().acquire(
                address,
                realChain.request(),
                0,
                Protocol.HTTP_2
            )
            
            realChain.connection = connection
        }
        
        // 创建 HTTP 编码器
        val httpCodec = connection.newHttpCodec(realChain)
        
        try {
            return httpCodec.readResponse()
        } finally {
            httpCodec.end()
        }
    }
}

3.4 自定义拦截器

日志拦截器

kotlin
class LoggingInterceptor : Interceptor {
    private val logger = Logger()
    
    override fun intercept(chain: Interceptor.Chain): Response {
        val request = chain.request()
        val start = System.nanoTime()
        
        logger.log(
            "\n--- REQUEST ---\n" +
            "${request.method} ${request.url}\n" +
            "${request.headers}\n" +
            "${request.body?.let { logger.logBody(it) }}"
        )
        
        val response = chain.proceed(request)
        
        val duration = (System.nanoTime() - start) / 1_000_000
        
        logger.log(
            "\n--- RESPONSE ---\n" +
            "${response.code} ${response.message}\n" +
            "${response.headers}\n" +
            "${response.body?.let { logger.logBody(it) }}\n" +
            "Duration: $duration ms"
        )
        
        return response
    }
}

认证拦截器

kotlin
class AuthInterceptor : Interceptor {
    private val tokenManager: TokenManager
    
    override fun intercept(chain: Interceptor.Chain): Response {
        val request = chain.request()
        
        // 添加 Token
        val token = tokenManager.getToken()
        val requestWithToken = request.newBuilder()
            .header("Authorization", "Bearer $token")
            .build()
        
        val response = chain.proceed(requestWithToken)
        
        // Token 过期,刷新后重试
        if (response.code == 401) {
            val newToken = tokenManager.refreshToken()
            val requestWithNewToken = request.newBuilder()
                .header("Authorization", "Bearer $newToken")
                .build()
            
            return chain.proceed(requestWithNewToken)
        }
        
        return response
    }
}

重试拦截器

kotlin
class RetryInterceptor : Interceptor {
    private val maxRetries = 3
    private val retryDelay = 1000L
    
    override fun intercept(chain: Interceptor.Chain): Response {
        var attempt = 0
        var response: Response
        
        while (true) {
            try {
                response = chain.proceed(chain.request())
                
                if (response.isSuccessful || !isRetryable(response.code)) {
                    return response
                }
                
            } catch (e: IOException) {
                if (attempt >= maxRetries || !isRetryable(e)) {
                    throw e
                }
            }
            
            attempt++
            Thread.sleep(retryDelay * attempt) // 指数退避
        }
    }
    
    private fun isRetryable(code: Int): Boolean {
        return code in listOf(408, 429, 500, 502, 503, 504)
    }
    
    private fun isRetryable(exception: IOException): Boolean {
        return exception is SocketTimeoutException || 
               exception is UnknownHostException
    }
}

连接池管理

4.1 连接池原理

连接池的作用

1. 复用 TCP 连接,减少握手开销
2. 控制并发连接数
3. 管理连接生命周期

连接池结构

ConnectionPool {
    // 空闲连接列表
    private val idleConnections: ConcurrentLinkedQueue<RealConnection>
    
    // 正在使用的连接
    private val connections: List<RealConnection>
    
    // 最大空闲连接数
    private val maxSize: Int
    
    // 空闲连接保持时间
    private val keepAliveDuration: Duration
    
    // 清理线程
    private val cleaner: ExecutorService
}

4.2 连接复用策略

域名级别复用

kotlin
// 同一域名的请求复用连接
val request1 = Request.Builder()
    .url("https://api.example.com/users")
    .build()

val request2 = Request.Builder()
    .url("https://api.example.com/posts")
    .build()

// request1 和 request2 会复用同一个 TCP 连接

HTTP/2 多路复用

kotlin
// HTTP/2 可以在同一个连接上并发多个请求
val client = OkHttpClient.Builder()
    .protocols(listOf(Protocol.HTTP_2, Protocol.HTTP_1_1))
    .build()

4.3 连接池配置

默认配置

kotlin
val client = OkHttpClient()
// 默认:maxSize=5, keepAlive=5 分钟

自定义配置

kotlin
val connectionPool = ConnectionPool().apply {
    // 最大空闲连接数
    maxSize = 10
    
    // 空闲连接保持时间
    keepAliveDuration = 10L, TimeUnit.MINUTES
    
    // 清理监听器
    evictionListener = { address, reason ->
        when (reason) {
            ConnectionPool.CLOSED -> {
                Log.d("Pool", "Connection closed: $address")
            }
            ConnectionPool.IDLE -> {
                Log.d("Pool", "Connection idle timeout: $address")
            }
            ConnectionPool.MAX_IDLE -> {
                Log.d("Pool", "Connection max idle: $address")
            }
        }
    }
}

val client = OkHttpClient.Builder()
    .connectionPool(connectionPool)
    .build()

4.4 连接池监控

监控连接池状态

kotlin
class ConnectionPoolMonitor {
    fun monitor(pool: ConnectionPool) {
        // 通过反射获取内部状态
        val idleConnectionsField = pool::class.java
            .getDeclaredField("idleConnections")
        idleConnectionsField.isAccessible = true
        
        val connectionsField = pool::class.java
            .getDeclaredField("connections")
        connectionsField.isAccessible = true
        
        val idleConnections = idleConnectionsField.get(pool) as Queue<*>
        val connections = connectionsField.get(pool) as List<*>
        
        Log.d("Pool", "Idle: ${idleConnections.size}, Total: ${connections.size}")
    }
}

4.5 连接池最佳实践

全局共享 OkHttpClient

kotlin
object ApiClient {
    private val connectionPool = ConnectionPool().apply {
        maxSize = 10
        keepAliveDuration = 10L, TimeUnit.MINUTES
    }
    
    val client: OkHttpClient by lazy {
        OkHttpClient.Builder()
            .connectionPool(connectionPool)
            .build()
    }
}

// ✅ 正确:全局共享
fun makeRequest() {
    ApiClient.client.newCall(request).execute()
}

// ❌ 错误:每次都创建新客户端
fun makeRequestWrong() {
    val client = OkHttpClient() // 不会复用连接池
    client.newCall(request).execute()
}

HTTP 缓存

5.1 缓存原理

HTTP 缓存标准

遵循 RFC 7234 HTTP Caching 标准

缓存控制头:
- Cache-Control
- Expires
- ETag
- Last-Modified

缓存验证流程

1. 检查强缓存(Cache-Control/Expires)
   └─ 有效 -> 直接返回缓存

2. 检查协商缓存(ETag/Last-Modified)
   └─ 未修改 -> 返回 304
   └─ 已修改 -> 返回新资源

3. 无缓存 -> 网络请求

5.2 配置 HTTP 缓存

创建缓存目录

kotlin
val cacheDir = context.cacheDir.resolve("http_cache")
val cacheSize = 100L * 1024 * 1024 // 100MB

val cache = Cache(cacheDir, cacheSize)

val client = OkHttpClient.Builder()
    .cache(cache)
    .build()

缓存策略配置

kotlin
// 强缓存 1 小时
val request = Request.Builder()
    .url("https://api.example.com/data")
    .header("Cache-Control", "max-age=3600")
    .build()

// 不使用缓存
val request = Request.Builder()
    .url("https://api.example.com/data")
    .header("Cache-Control", "no-cache")
    .build()

// 离线模式(只使用缓存)
val request = Request.Builder()
    .url("https://api.example.com/data")
    .header("Cache-Control", "only-if-cached, max-stale=604800")
    .build()

5.3 缓存拦截器

自定义缓存策略

kotlin
class CacheControlInterceptor : Interceptor {
    override fun intercept(chain: Interceptor.Chain): Response {
        val request = chain.request()
        
        // 检查网络状态
        val isConnected = isNetworkAvailable()
        
        if (!isConnected) {
            // 离线模式
            val offlineRequest = request.newBuilder()
                .removeHeader("Pragma")
                .header("Cache-Control", "public, only-if-cached, max-stale=604800")
                .build()
            
            val response = chain.proceed(offlineRequest)
            
            if (response.code == 504) {
                return Response.Builder()
                    .request(offlineRequest)
                    .protocol(response.protocol)
                    .code(504)
                    .message("Offline")
                    .body(ResponseBody.create(null, "离线"))
                    .build()
            }
            
            return response
        }
        
        // 在线模式
        val onlineRequest = request.newBuilder()
            .removeHeader("Pragma")
            .header("Cache-Control", "max-age=3600")
            .build()
        
        val response = chain.proceed(onlineRequest)
        
        // 添加缓存头
        return response.newBuilder()
            .header("Cache-Control", "max-age=3600")
            .build()
    }
}

5.4 缓存管理

清除缓存

kotlin
// 清除单个缓存
cache.remove(request)

// 清除所有缓存
cache.evictAll()

// 清理过期缓存
cache.cleanUp()

缓存统计

kotlin
val cache = client.cache!!
val size = cache.size()
val maxSize = cache.maximumSize()
val requestCount = cache.requestCount()
val networkCount = cache.networkCount()

异步请求

6.1 异步执行机制

Dispatcher 调度器

kotlin
class Dispatcher {
    // 异步请求线程池
    private val executorService: ExecutorService = ThreadPoolExecutor(
        0,
        Int.MAX_VALUE,
        60L,
        TimeUnit.SECONDS,
        SynchronousQueue(),
        ThreadFactory.Builder("OkHttp Dispatcher").build()
    )
    
    // 最大并发数
    private var maxRequests = 64
    
    // 每主机最大并发数
    private var maxRequestsPerHost = 5
    
    // 正在执行的异步请求
    private val runningAsyncCalls: AtomicInteger
    
    // 等待的异步请求
    private val readyAsyncCalls: Deque<AsyncCall>
    
    // 正在执行的同步请求
    private val runningSyncCalls: AtomicInteger
    
    // 等待的同步请求
    private val readySyncCalls: Deque<AsyncCall>
}

执行流程

1. enqueue() 添加到 Dispatcher
2. Dispatcher 检查并发限制
3. 从线程池获取线程
4. 执行请求
5. 回调结果
6. 释放资源

6.2 异步请求实现

enqueue 执行

kotlin
override fun enqueue(responseCallback: Callback) {
    val asyncCall = toAsyncCall()
    
    // 检查是否已执行或已取消
    if (asyncCall.eventCount != 0) {
        throw IllegalStateException("Already executed")
    }
    
    // 添加到调度器
    client.dispatcher().enqueue(asyncCall)
}

// AsyncCall 实现 Runnable
private inner class AsyncCall(
    private val call: RealCall,
    private val responseCallback: Callback
) : Runnable {
    override fun run() {
        try {
            val response = call.getReadResponse()
            responseCallback.onResponse(this, response)
        } catch (e: IOException) {
            responseCallback.onFailure(this, e)
        }
    }
}

6.3 协程支持

使用 suspend 函数

kotlin
// 添加协程适配器
val retrofit = Retrofit.Builder()
    .addCallAdapterFactory(CoroutineCallAdapterFactory())
    .build()

interface ApiService {
    @GET("users")
    suspend fun getUsers(): List<User>
}

// 使用
lifecycleScope.launch {
    try {
        val users = apiService.getUsers()
        // 处理结果
    } catch (e: Exception) {
        // 处理错误
    }
}

手动实现协程调用

kotlin
suspend fun <T> Call.await(): Response<T> {
    return suspendCancellableCoroutine { continuation ->
        enqueue(object : Callback {
            override fun onFailure(call: Call, e: IOException) {
                continuation.resumeWith(Result.failure(e))
            }
            
            override fun onResponse(call: Call, response: Response) {
                continuation.resumeWith(Result.success(response))
            }
        })
        
        continuation.invokeOnCancellation {
            cancel()
        }
    }
}

// 使用
val response = call.await()

6.4 并发控制

限制并发数

kotlin
val dispatcher = Dispatcher().apply {
    maxRequests = 32  // 总并发数
    maxRequestsPerHost = 3  // 每主机并发数
}

val client = OkHttpClient.Builder()
    .dispatcher(dispatcher)
    .build()

自定义线程池

kotlin
val executor = ThreadPoolExecutor(
    4,
    16,
    60L,
    TimeUnit.SECONDS,
    LinkedBlockingQueue(100),
    ThreadFactory.Builder("Custom OkHttp").build(),
    ThreadPoolExecutor.CallerRunsPolicy()
)

val dispatcher = Dispatcher(executor)

源码分析

7.1 Request 到 Response 的完整流程

详细流程

kotlin
fun execute(request: Request): Response {
    // 1. 创建 RealCall
    val call = client.newCall(request)
    
    // 2. 执行拦截器链
    val response = call.execute()
    
    return response
}

// RealCall.execute()
fun execute(): Response {
    // 3. 检查是否已执行
    check(!executed)
    
    // 4. 构建拦截器链
    val interceptors = buildInterceptorChain()
    
    // 5. 执行链
    val response = proceedInterceptors(interceptors)
    
    return response
}

// 构建拦截器链
fun buildInterceptorChain(): List<Interceptor> {
    return mutableListOf<Interceptor>().apply {
        // 应用拦截器
        addAll(client.applicationInterceptors)
        
        // 内置拦截器
        add(RetryAndFollowUpInterceptor(client))
        add(BridgeInterceptor(client.cookieJar))
        add(FollowUpInterceptor(client))
        add(CacheInterceptor(client.cache))
        add(ConnectInterceptor(client))
        
        // 网络拦截器
        addAll(client.networkInterceptors)
        
        // 核心拦截器
        add(ResponseSourceInterceptor())
    }
}

7.2 连接获取流程

连接获取

kotlin
fun acquire(address: Address, request: Request): RealConnection {
    // 1. 尝试复用现有连接
    for (connection in connections) {
        if (connection.isHealthy() && connection.route.address == address) {
            return connection
        }
    }
    
    // 2. 尝试复用空闲连接
    val idleConnection = idleConnections.pollFirst()
    if (idleConnection != null && idleConnection.isHealthy()) {
        return idleConnection
    }
    
    // 3. 创建新连接
    val newConnection = RealConnection(client, address)
    newConnection.connect()
    
    return newConnection
}

7.3 HTTP/2 支持

HTTP/2 协商

kotlin
// ALPN 协议协商
class AlpnEventAdapter {
    override fun selectProtocol(
        protocols: List<Protocol>
    ): Protocol {
        // 尝试 HTTP/2
        if (protocols.contains(Protocol.H2_PRIOR_KNOWLEDGE)) {
            return Protocol.H2_PRIOR_KNOWLEDGE
        }
        
        if (protocols.contains(Protocol.HTTP_2)) {
            return Protocol.HTTP_2
        }
        
        return Protocol.HTTP_1_1
    }
}

7.4 超时处理

超时机制

kotlin
class Timeout {
    private val timeoutDuration: Long
    private var deadline: Long = 0
    
    fun enter() {
        // 检查是否超时
        if (System.nanoTime() > deadline) {
            throw IOException("Timeout")
        }
        
        // 设置 deadline
        deadline = System.nanoTime() + timeoutDuration
    }
    
    fun remain(): Long {
        return maxOf(0, deadline - System.nanoTime())
    }
}

性能调优

8.1 连接池调优

优化参数

kotlin
val connectionPool = ConnectionPool().apply {
    // 根据业务调整最大连接数
    maxSize = 20  // 默认 5
    
    // 延长空闲时间
    keepAliveDuration = 15L, TimeUnit.MINUTES  // 默认 5
}

监控连接复用

kotlin
val connectionPool = ConnectionPool().apply {
    evictionListener = { address, reason ->
        // 记录连接被移除的情况
        Log.d("Connection", "Removed: $address, Reason: $reason")
    }
}

8.2 缓存调优

优化缓存大小

kotlin
// 根据可用空间调整
val cacheSize = Runtime.getRuntime().maxMemory() / 10
val cache = Cache(cacheDir, cacheSize)

8.3 并发调优

调整并发限制

kotlin
val dispatcher = Dispatcher().apply {
    // 根据业务调整
    maxRequests = 32
    maxRequestsPerHost = 5
}

8.4 网络层调优

DNS 优化

kotlin
class DnsCache : Dns {
    private val cache = LruCache<String, List<InetSocketAddress>>(100)
    
    override fun lookup(hostname: String): List<InetSocketAddress> {
        return cache.get(hostname) ?: run {
            val result = InetAddress.getAllByName(hostname)
                .toList()
                .map { InetSocketAddress(it, 443) }
            cache.put(hostname, result)
            result
        }
    }
}

val client = OkHttpClient.Builder()
    .dns(DnsCache())
    .build()

TCP 优化

kotlin
// 启用 TCP_NODELAY(禁用 Nagle 算法)
SocketFactory().apply {
    val socket = createSocket(host, port)
    socket.tcpNoDelay = true
}

代码示例

9.1 完整的 OkHttp 配置

kotlin
object OkHttpConfig {
    
    private fun createConnectionPool(): ConnectionPool {
        return ConnectionPool().apply {
            maxSize = 10
            keepAliveDuration = 10L, TimeUnit.MINUTES
        }
    }
    
    private fun createCache(context: Context): Cache {
        val cacheDir = context.cacheDir.resolve("http_cache")
        val cacheSize = 100L * 1024 * 1024 // 100MB
        
        return Cache(cacheDir, cacheSize)
    }
    
    private fun createLoggingInterceptor(): Interceptor {
        val logger = Logger().apply {
            level = Logger.Level.BODY
        }
        
        return HttpLoggingInterceptor(logger).apply {
            level = Level.BODY
        }
    }
    
    private fun createAuthInterceptor(): Interceptor {
        return object : Interceptor {
            override fun intercept(chain: Interceptor.Chain): Response {
                val request = chain.request().newBuilder()
                    .addHeader("Authorization", "Bearer ${getToken()}")
                    .addHeader("X-App-Version", BuildConfig.VERSION_NAME)
                    .build()
                
                return chain.proceed(request)
            }
        }
    }
    
    val client: OkHttpClient by lazy {
        OkHttpClient.Builder()
            // 连接池
            .connectionPool(createConnectionPool())
            
            // 缓存
            .cache(createCache(Application.application))
            
            // 超时
            .connectTimeout(10, TimeUnit.SECONDS)
            .readTimeout(30, TimeUnit.SECONDS)
            .writeTimeout(30, TimeUnit.SECONDS)
            .callTimeout(45, TimeUnit.SECONDS)
            
            // 重试
            .retryOnConnectionFailure(true)
            
            // 协议
            .protocols(listOf(Protocol.HTTP_2, Protocol.HTTP_1_1))
            
            // 拦截器
            .addInterceptor(createLoggingInterceptor())
            .addInterceptor(createAuthInterceptor())
            
            // DNS
            .dns(DnsCache())
            
            // 调度器
            .dispatcher(Dispatcher().apply {
                maxRequests = 32
                maxRequestsPerHost = 5
            })
            
            .build()
    }
}

9.2 完整的请求示例

kotlin
class ApiService {
    
    private val client = OkHttpConfig.client
    private val retrofit = Retrofit.Builder()
        .baseUrl("https://api.example.com/")
        .client(client)
        .addConverterFactory(GsonConverterFactory.create())
        .addCallAdapterFactory(CoroutineCallAdapterFactory())
        .build()
    
    interface UserApi {
        @GET("users/{id}")
        suspend fun getUser(@Path("id") id: String): User
        
        @POST("users")
        suspend fun createUser(@Body user: User): User
        
        @Multipart
        @POST("upload")
        suspend fun uploadFile(@Part file: MultipartBody.Part): UploadResult
    }
    
    private val userApi = retrofit.create(UserApi::class.java)
    
    // 获取用户
    suspend fun getUser(id: String): Result<User> {
        return try {
            val user = userApi.getUser(id)
            Result.success(user)
        } catch (e: IOException) {
            Result.failure(e)
        }
    }
    
    // 创建用户
    suspend fun createUser(user: User): Result<User> {
        return try {
            val result = userApi.createUser(user)
            Result.success(result)
        } catch (e: IOException) {
            Result.failure(e)
        }
    }
    
    // 上传文件
    suspend fun uploadFile(file: File): Result<UploadResult> {
        return try {
            val requestBody = file.asRequestBody(ContentType.parse("image/jpeg"))
            val body = MultipartBody.Part.createFormData("file", file.name, requestBody)
            
            val result = userApi.uploadFile(body)
            Result.success(result)
        } catch (e: IOException) {
            Result.failure(e)
        }
    }
}

面试考点

基础题

1. OkHttp 的核心组件?

- OkHttpClient:客户端配置
- Call:请求调用
- Dispatcher:调度器
- Interceptor:拦截器
- ConnectionPool:连接池
- Cache:缓存

2. OkHttp 的拦截器类型?

1. 应用拦截器:拦截所有请求
2. 网络拦截器:只拦截网络请求

内置拦截器:
- RetryAndFollowUpInterceptor
- BridgeInterceptor
- CacheInterceptor
- ConnectInterceptor

3. 连接池的工作原理?

1. 复用 TCP 连接
2. 按域名管理连接
3. 超时自动清理
4. 全局共享 OkHttpClient

进阶题

1. OkHttp 的拦截器执行顺序?

1. Application Interceptors
2. RetryAndFollowUpInterceptor
3. BridgeInterceptor
4. CacheInterceptor
5. ConnectInterceptor
6. Network Interceptors
7. RealCall 执行

2. 如何实现请求重试?

方式 1: 使用内置重试(RetryAndFollowUpInterceptor)
方式 2: 自定义拦截器实现重试
方式 3: 使用 OkHttp 的 retryOnConnectionFailure

3. 如何优化 OkHttp 性能?

1. 全局共享 OkHttpClient
2. 合理配置连接池
3. 启用 HTTP/2
4. 优化缓存策略
5. DNS 缓存
6. 调整并发限制

高级题

1. OkHttp 如何处理 HTTP/2?

1. ALPN 协议协商
2. 使用 Http2Codec 编码解码
3. 多路复用
4. 头部压缩(HPACK)
5. 流控

2. OkHttp 的缓存机制?

遵循 HTTP Caching 标准
- 强缓存(Cache-Control)
- 协商缓存(ETag)
- 磁盘缓存 + 内存缓存

3. 如何实现自定义连接管理?

实现 ConnectionPool
自定义 Address
实现 RouteDatabase

总结

核心要点

  1. 架构设计

    • 拦截器链模式
    • 异步调度器
    • 连接池管理
  2. 性能优化

    • 连接复用
    • HTTP/2 支持
    • 缓存机制
    • 并发控制
  3. 扩展性

    • 拦截器扩展
    • 自定义组件
    • 协程支持

最佳实践

kotlin
// 1. 全局共享 OkHttpClient
object ApiClient {
    val client: OkHttpClient = ...
}

// 2. 合理配置连接池
.connectionPool(ConnectionPool(10, 10, MINUTES))

// 3. 启用 HTTP/2
.protocols(listOf(HTTP_2, HTTP_1_1))

// 4. 使用拦截器扩展
.addInterceptor(authInterceptor)

// 5. 协程支持
.addCallAdapterFactory(CoroutineCallAdapterFactory())

本文约 15000 字,涵盖了 OkHttp 底层的核心知识点。