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与磁盘缓存)
相关推荐
酷小洋2 天前
Ajax基础
前端·ajax·okhttp
人间有清欢4 天前
Android开发补充内容
android·okhttp·rxjava·retrofit·hilt·jetpack compose
diaostar6 天前
Android OKHttp原理简单说明
android·okhttp
yuren_xia13 天前
Spring MVC 中解决中文乱码问题
spring·okhttp·mvc
我要喝可乐!14 天前
OkHttp源码梳理
网络协议·http·okhttp
前端熊猫17 天前
jQuery AJAX、Axios与Fetch
ajax·okhttp·jquery
程序员沉梦听雨18 天前
OkHttp入门
okhttp
隐-梵18 天前
Android studio进阶开发(四)--okhttp的网络通信的使用
android·ide·okhttp·android studio
星之卡比*19 天前
前端面试题---GET跟POST的区别(Ajax)
前端·ajax·okhttp