okhttp原理

一、核心架构与设计模式

  1. 拦截器链(Interceptor Chain)
    • 责任链模式:通过 RealInterceptorChain 按顺序执行拦截器,每个拦截器可修改请求/响应

• 五大核心拦截器(按执行顺序):

  1. RetryAndFollowUpInterceptor:处理重定向和失败重试

    ◦ 自动重试机制:通过 StreamAllocation 寻找新的路由(Route)和连接(Connection)

    ◦ 最多重试次数:20次(源码常量 MAX_FOLLOW_UPS

  2. BridgeInterceptor:补全请求头(User-Agent, Cookie等)

    ◦ 自动添加 Content-TypeContent-Length 等必要头信息

  3. CacheInterceptor:缓存管理(基于HTTP缓存协议)

    ◦ 使用 CacheStrategy 判断是否使用缓存(根据 Cache-Control 头)

  4. ConnectInterceptor:建立网络连接

    ◦ 关键类 RealConnection:封装TCP/TLS连接,复用连接的关键

  5. CallServerInterceptor:发送请求并读取响应

    ◦ 通过 HttpCodec 处理HTTP协议编解码

  6. 连接池(ConnectionPool)

    • 复用机制:通过 ConnectionPool 管理空闲连接(默认最大空闲连接数5,存活时间5分钟)

java 复制代码
public ConnectionPool(int maxIdleConnections, long keepAliveDuration) {
  this.maxIdleConnections = maxIdleConnections; // 默认5
  this.keepAliveDurationNs = keepAliveDuration; // 默认5分钟
}

• 连接复用条件:相同Host + 相同SocketFactory + 相同代理配置

• LRU清理策略:后台线程定期清理过期/空闲连接


二、异步请求与线程管理

高频考点:Dispatcher 工作机制、线程池配置

  1. Dispatcher 调度器
    • 异步请求队列:维护两个队列

runningAsyncCalls:正在执行的异步请求(默认最大64)

readyAsyncCalls:等待执行的异步请求

executorService:线程池(核心线程数0,最大线程数Integer.MAX_VALUE)

• 最大并发请求数:默认同一域名最大5个并发(通过 Dispatcher.setMaxRequestsPerHost 设置)

线程池优化

• CachedThreadPool:避免频繁创建/销毁线程

java 复制代码
public synchronized ExecutorService executorService() {
  if (executorService == null) {
    executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS,
        new SynchronousQueue<>(), Util.threadFactory("OkHttp Dispatcher", false));
  }
  return executorService;
}

2.同步请求队列 runningSyncCalls


三、关键源码解析

高频考点:同步/异步请求流程、连接复用实现

  1. 请求执行流程
    • 同步请求:
java 复制代码
// OkHttpClient.newCall(request).execute()
public Response execute() {
  synchronized (this) {
    // 检查是否已执行
    executed = true;
  }
  transmitter.timeoutEnter(); // 超时管理
  transmitter.prepareToConnect(request);
  // 加入运行队列
  client.dispatcher().executed(this);
  // 执行拦截器链
  return getResponseWithInterceptorChain();
}

• 异步请求:

enqueue实际上是new了一个RealCall的内部类AsyncCall扔进了dispatcher中,如果当前正在运行的异步请求数小于阈值maxRequests (默认Dispatcher中为64)并且同host下运行的请求小于阈值maxRequestsPerHost(默认Dispatcher中为5),就将AsyncCall添加到正在运行的异步队里,并通过线程池异步执行,否则就将其丢到等待队列排队。

java 复制代码
// OkHttpClient.newCall(request).enqueue(callback)
void enqueue(AsyncCall call) {
  synchronized (this) {
    readyAsyncCalls.add(call);
  }
  promoteAndExecute(); // 调度执行
}
  1. 连接复用实现
    • RealConnection 复用逻辑:
java 复制代码
// StreamAllocation.findConnection()
if (connection != null) {
  releasedConnection = this.connection;
  result = releasedConnection;
  releasedConnection = null;
  if (!result.isEligible(address.url().host(), address.url().host())) {
    result = null;
  }
}

四、高频面试题与答案

  1. OkHttp如何实现连接复用?

    • 通过ConnectionPool管理空闲连接,复用相同Host+Port的连接

    • 使用Connection: keep-alive头实现HTTP/1.1长连接

  2. 拦截器执行顺序是怎样的?

    • RetryAndFollowUp → Bridge → Cache → Connect → CallServer

  3. 如何优化大文件下载?

    • 使用OkHttpClient配置连接/读取超时

    • 通过拦截器实现分块下载(Range头)

  4. 如何处理SSL/TLS握手?

    • 使用SSLSocketFactoryHostnameVerifier

    • 证书锁定(Certificate Pinning)示例:

    java 复制代码
    CertificatePinner pinner = new CertificatePinner.Builder()
        .add("publicobject.com", "sha256/AAAAAAAAAAAAAAAAAAAAAAAA=")
        .build();
  5. 使用到的设计模式

• 策略模式(在CacheInterceptor中,在响应数据的选择中使用了策略模式,选择缓存数据还是选择网络访问。)

• 责任链模式(拦截器的链式调用)


五、总结

OkHttp面试题核心要点:

  1. 拦截器链责任链模式的执行顺序与作用
  2. 连接池管理策略(LRU、最大空闲数)
  3. Dispatcher异步调度机制与线程池配置
  4. 缓存策略(Cache-Control与磁盘缓存)
相关推荐
凌冰_3 天前
Vue 使用Ajax异步或同步
前端·ajax·okhttp
nee~3 天前
Charles抓包
okhttp
赵得C14 天前
AJAX拦截器失效排查指南:当你的beforeSend有效但error/complete沉默时
前端·ajax·okhttp
粤M温同学18 天前
Android OkHttp 框架超时设置详解
android·okhttp
粤M温同学18 天前
Android 使用OkHttp 下载文件失败问题定位和修复
okhttp
CUIYD_198919 天前
Ajax 核心知识点全面总结
前端·ajax·okhttp
weixin_4383354019 天前
Spring RestTemplate + MultiValueMap vs OkHttp 多值参数的处理
java·spring·okhttp
网络点点滴22 天前
上传一个菜谱-最后部分(项目完结)
android·okhttp
农业工作者22 天前
Android:使用OkHttp
android·okhttp
androidwork22 天前
Android 中 OkHttp 的自定义 Interceptor 实现统一请求头添加
android·java·okhttp·kotlin