OkHttp源码梳理

目录

一、基本使用

[1 创建 OkHttpClient](#1 创建 OkHttpClient)

[2 构建请求 Request](#2 构建请求 Request)

[3 创建和执行 Call](#3 创建和执行 Call)

二、OkHttp请求整体流程

[1. 用户调用入口](#1. 用户调用入口)

[2. RealCall执行逻辑](#2. RealCall执行逻辑)

[2.1 同步请求:RealCall.execute()](#2.1 同步请求:RealCall.execute())

[2.2 异步请求:RealCall.enqueue(Callback)](#2.2 异步请求:RealCall.enqueue(Callback))

[3. Dispatcher调度请求](#3. Dispatcher调度请求)

[4. 拦截器链 getResponseWithInterceptorChain()](#4. 拦截器链 getResponseWithInterceptorChain())

[三、OkHttp 内置 Interceptor 总结](#三、OkHttp 内置 Interceptor 总结)

[1. ​​重试与重定向拦截器(RetryAndFollowUpInterceptor)​​](#1. 重试与重定向拦截器(RetryAndFollowUpInterceptor))

[2. ​​桥接拦截器(BridgeInterceptor)​​](#2. 桥接拦截器(BridgeInterceptor))

[3. ​​缓存拦截器(CacheInterceptor)​​](#3. 缓存拦截器(CacheInterceptor))

[4. ​​连接拦截器(ConnectInterceptor)​​](#4. 连接拦截器(ConnectInterceptor))

[5. ​​网络拦截器(CallServerInterceptor)​​](#5. 网络拦截器(CallServerInterceptor))


一、基本使用

1 创建 OkHttpClient

  • 全局配置中心

  • 可以通过 Builder 配置:

    • 连接超时、读写超时

    • 连接池(ConnectionPool)

    • 拦截器(Interceptor)

    • 事件监听(EventListener)

    • 代理设置、证书配置等


2 构建请求 Request

Request用于描述单次请求的参数信息,支持各种 HTTP 方法(GET、POST、PUT、DELETE...),也可以带 Header、Body。

复制代码

3 创建和执行 Call

  • Call 是一次请求的抽象。

  • 可以同步 (execute) 或异步 (enqueue) 执行。

  • 同步请求,会阻塞线程,不能直接在主线程当中调用

  • 异步请求默认在子线程,自己切换线程。


二、OkHttp请求整体流程

1. 用户调用入口

无论是同步请求(execute()),还是异步请求(enqueue()),都是从RealCall开始的:

复制代码
  • OkHttpClient.newCall(Request):返回一个 RealCall。

  • RealCall 是 OkHttp 处理每个请求的真正执行类。


2. RealCall执行逻辑

2.1 同步请求:RealCall.execute()

复制代码

2.2 异步请求:RealCall.enqueue(Callback)

复制代码
  • okhttp会把异步请求包装成一个 AsyncCall

  • AsyncCall实现了Runnable接口,重写了run方法,并在run方法中调getResponseWithInterceptorChain()


3. Dispatcher调度请求

  • 同步:直接加入 runningSyncCalls。

  • 异步:

    • 先加入 readyAsyncCalls 等待排队,

    • 再调用promoteAndExecute()函数从异步任务等待队列选举任务并执行,选举时遍历等待队列,检查当前总请求数有没有达到上限,当前同一主机名请求数有没有达到上限,通过后交给线程池执行

最终都会执行 getResponseWithInterceptorChain(),进入真正的拦截器链处理流程。


4. 拦截器链 getResponseWithInterceptorChain()

该方法会按一定的顺序 构建拦截器列表interceptors,接着利用interceptors创建RealInterceptorChain对象,该对象是一条责任链,使用了责任链模式。

请求从上往下交付,每个拦截器拿到请求都可以对请求做出相应处理,然后交给下一个拦截器,最后一个拦截器处理请求拿到响应后,将响应从下往上交付,每个拦截器拿到响应后再对响应做出相应处理,然后交给上一个拦截器。


拦截器 作用
用户自定义应用拦截器 可以操作请求/响应,记录日志,加签名认证等
RetryAndFollowUpInterceptor 负责失败重试、重定向
BridgeInterceptor 请求标准化,响应标准化,添加必要头部,响应体解码
CacheInterceptor 读取缓存,更新缓存
ConnectInterceptor 建立与服务器的连接
用户自定义网络拦截器 观察实际请求/响应报文(仅对真正走网络的请求)
CallServerInterceptor 发送请求到服务器、接收响应

三、OkHttp 内置 Interceptor 总结

1. ​​重试与重定向拦截器(RetryAndFollowUpInterceptor)​​

  • ​作用​:处理请求失败时的自动重试和 HTTP 重定向(如 302 跳转)。

  • ​关键行为​ :

    • 检测可恢复的异常(如连接超时、Socket 断开)并重试请求。
    • 遵循 HTTP 协议的重定向响应(如 301/302/307),自动跳转到新 URL。
    • 限制最大重试次数(默认 20 次)和重定向次数。
  • ​示例场景​ :

    复制代码
    // 当服务器返回 302 时,自动请求新的 Location 地址
    Response response = client.newCall(request).execute(); // 无需手动处理跳转

2. ​​桥接拦截器(BridgeInterceptor)​​

  • ​作用​:在应用代码和网络请求之间"桥接",补充必要协议头并处理响应解码。

  • ​关键行为​ :

    • 自动添加缺失的 HTTP 头(如 Host、Content-Type、Accept-Encoding: gzip)。
    • 处理 CookieJar 的自动注入(如果配置了 Cookie 管理器)。
    • 解压 Gzip 压缩的响应体(透明解压,对应用层无感知)。
  • ​示例补充的请求头​ :

    复制代码
    Accept-Encoding: gzip
    User-Agent: okhttp/4.10.0
    Connection: keep-alive

3. ​​缓存拦截器(CacheInterceptor)​​

  • ​作用​:根据 HTTP 缓存策略管理本地缓存,减少重复网络请求。

  • ​关键行为​ :

    • 检查请求是否符合缓存条件(如 Cache-Control 头)。
    • 返回缓存响应(如果未过期且有效)。
    • 缓存服务器返回的新响应(如果配置了缓存目录)。
  • ​缓存配置示例​ :

    复制代码
    OkHttpClient client = new OkHttpClient.Builder()
        .cache(new Cache(new File("cacheDir"), 10 * 1024 * 1024)) // 10MB 缓存
        .build();

4. ​​连接拦截器(ConnectInterceptor)​​

  • ​作用​:建立与目标服务器的 TCP/TLS 连接(或复用连接池中的连接)。
  • ​关键行为​ :
    • 从连接池中复用空闲连接(减少 TCP 握手开销)。
    • 必要时创建新连接(支持 HTTP/1.1、HTTP/2 或 WebSocket)。
    • 处理 TLS 握手(HTTPS 请求)。
  • ​性能优化​ :
    • 默认连接池最多维护 5 个空闲连接,存活时间 5 分钟。

5. ​​网络拦截器(CallServerInterceptor)​​

  • ​作用​:最终向服务器发送请求数据并读取响应,完成网络 I/O 操作。
  • ​关键行为​ :
    • 写入请求头和请求体(通过 Socket 输出流)。
    • 读取响应头和响应体(通过 Socket 输入流)。
    • 处理分块传输编码(Transfer-Encoding: chunked)。
    • 关闭连接(如果未启用 keep-alive)。
  • ​底层细节​ :
    • 使用 Okio 库高效读写数据流。
相关推荐
明天也要努力学习17 小时前
HTTP 协议的基本格式和 fiddler 的用法
网络协议·http·fiddler
cpolar技术支持21 小时前
网关加 gzip,同时开启 chunked,下载回来的包解不开:把两层编码的解压顺序与长度核对做成只读页
python·http·网络编程·socket·内网穿透
Tel199253080041 天前
温度湿度信号转WiFi/MQTT/Modbus TCP采集模块 无线传输
网络·网络协议·tcp/ip·工业自动化·工控设备
lazy H1 天前
【计算机网络】第 13 篇:NAT 和端口映射是什么?为什么本地服务外网访问不了?
java·网络·网络协议·学习·计算机网络·408
低慢小uav1 天前
(已解决)Zynq芯片lwip协议栈,使用tcp作为服务器Service,接收大量数据时,长度接收正常,接收对数据校验,校验和异常分析
网络协议·tcp/ip·fpga开发
骑着蜗牛撵大象3271 天前
手写一个 HTTP 服务器:从 socket 到 epoll,Linux 上到底怎么把请求变成响应
linux·服务器·网络·http·epoll·socket编程·并发模型
沫璃染墨1 天前
从零入门计算机网络系列(十):HTTP协议进阶——从资源路径解析到状态码与请求头详解
linux·运维·服务器·网络·c++·http
|_⊙1 天前
应用层协议HTTP与HTTPS
网络·网络协议·http
byte轻骑兵1 天前
【PBAP】规范精讲[9]: 蓝牙PBAP的互联互通法则——GOEP互操作性要求深度解析
网络协议·人机交互·蓝牙协议·pbap
路由侠内网穿透.1 天前
本地部署开源 WSGI HTTP 服务器 Gunicorn 并实现外部访问
运维·服务器·网络·网络协议·http·开源