OkHttp:工作原理 拦截器链深度解析

news2025/3/9 7:34:24

目录

一、OKHttp 的基本使用

1. 添加依赖

2. 发起 HTTP 请求

3. 拦截器(Interceptor)

4. 高级配置

二、OKHttp 核心原理

1. 责任链模式(Interceptor Chain)

2. 连接池(ConnectionPool)

3. 请求调度(Dispatcher)

4. 缓存机制

5. 其他特性

三、拦截器工作原理

3.1 拦截器链的执行顺序

3.2 五大拦截器的工作原理

3.3 拦截器协作流程图

3.4 关键场景分析

3.5 总结

四、常见问题与优化

五、总结


OKHttp 是一款高效的 HTTP 客户端库,由 Square 公司开发,支持 Android 和 Java 应用。它简化了 HTTP 请求处理,支持同步/异步请求、连接池、缓存、拦截器等特性。以下是其使用流程图和原理的详细解析:


一、OKHttp 的基本使用

1. 添加依赖

在 Gradle 中添加依赖:

implementation 'com.squareup.okhttp3:okhttp:4.9.3' // 最新版本以官方为准
2. 发起 HTTP 请求

同步请求示例:

OkHttpClient client = new OkHttpClient();

Request request = new Request.Builder()
    .url("https://api.example.com/data")
    .build();

try (Response response = client.newCall(request).execute()) {
    if (response.isSuccessful()) {
        String responseData = response.body().string();
        System.out.println(responseData);
    }
} catch (IOException e) {
    e.printStackTrace();
}

注意: 同步请求需在子线程执行(Android 中主线程禁止网络操作)。

异步请求示例:

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 {
        if (response.isSuccessful()) {
            String responseData = response.body().string();
            // 注意:回调在后台线程,需切换线程更新 UI
        }
    }
});
3. 拦截器(Interceptor)

拦截器用于监控、修改请求和响应。例如添加统一请求头:

OkHttpClient client = new OkHttpClient.Builder()
    .addInterceptor(new Interceptor() {
        @Override
        public Response intercept(Chain chain) throws IOException {
            Request originalRequest = chain.request();
            Request newRequest = originalRequest.newBuilder()
                .header("Authorization", "Bearer token")
                .build();
            return chain.proceed(newRequest);
        }
    })
    .build();
4. 高级配置
OkHttpClient client = new OkHttpClient.Builder()
    .connectTimeout(10, TimeUnit.SECONDS) // 连接超时
    .readTimeout(30, TimeUnit.SECONDS)    // 读取超时
    .writeTimeout(30, TimeUnit.SECONDS)   // 写入超时
    .cookieJar(new CookieJar() {          // Cookie 管理
        private final HashMap<HttpUrl, List<Cookie>> cookieStore = new HashMap<>();
        @Override
        public void saveFromResponse(HttpUrl url, List<Cookie> cookies) {
            cookieStore.put(url, cookies);
        }
        @Override
        public List<Cookie> loadForRequest(HttpUrl url) {
            return cookieStore.getOrDefault(url, new ArrayList<>());
        }
    })
    .build();

二、OKHttp 核心原理

1. 责任链模式(Interceptor Chain)

OKHttp 的核心是 拦截器链,每个请求会依次经过多个拦截器处理:

  • 自定义拦截器:开发者添加的拦截器,最先执行。

  • RetryAndFollowUpInterceptor:处理重定向和失败重试。

  • BridgeInterceptor:补全请求头(如 Content-TypeCookie)。

  • CacheInterceptor:根据缓存策略返回缓存或请求网络。

  • ConnectInterceptor:建立与服务器的连接(复用连接池中的连接)。

  • CallServerInterceptor:向服务器发送请求并读取响应。

2. 连接池(ConnectionPool)
  • 作用:复用 TCP 连接,减少握手开销。

  • 默认配置:最大空闲连接数 5,存活时间 5 分钟。

  • 实现:通过 RealConnectionPool 管理空闲连接,清理过期连接。

3. 请求调度(Dispatcher)
  • 同步请求:直接执行,但需开发者自行管理线程。

  • 异步请求:通过 Dispatcher 管理线程池,默认最大并发请求数 64,单个域名最大并发 5。

4. 缓存机制
  • 基于 HTTP 缓存协议(如 Cache-ControlETag)。

  • 缓存目录需开发者指定,通过 Cache 类配置:

    Cache cache = new Cache(context.getCacheDir(), 10 * 1024 * 1024); // 10MB 缓存
    OkHttpClient client = new OkHttpClient.Builder().cache(cache).build();
5. 其他特性
  • HTTP/2 支持:多路复用、头部压缩。

  • WebSocket:通过 okhttp-ws 模块支持长连接。

  • HTTPS:支持 TLS 1.3,可配置证书校验策略。


三、拦截器工作原理

OKHttp 的五大核心拦截器构成了其高效的网络请求处理链,每个拦截器职责明确,协同工作。以下是它们的详细工作流程和原理:

3.1 拦截器链的执行顺序

OKHttp 的请求处理基于责任链模式,五大核心拦截器按固定顺序依次处理请求和响应:请求从第一个拦截器进入,逐步传递到最后一个拦截器(CallServerInterceptor),响应则逆向返回


3.2 五大拦截器的工作原理

1. RetryAndFollowUpInterceptor

核心职责:处理请求失败的重试与重定向。

  • 重试机制
    若请求因网络问题(如连接超时、IO 异常)失败,根据配置决定是否重试(默认最多 20 次)。

  • 重定向处理
    若服务器返回 3xx 状态码(如 302 临时跳转),自动构建新请求并重新发起。

  • 流程示例

    Request → RetryAndFollowUpInterceptor → 发送请求 → 失败 → 判断是否重试 → 重新执行链  
    Response ← 处理重定向 → 生成新 Request → 重新执行链

2. BridgeInterceptor

核心职责:桥接应用代码与网络请求,补充请求头、处理 Cookie 和响应编码。

  • 请求头补充
    自动添加 User-AgentHostContent-Type 等头信息。
    若请求体为 RequestBody,自动计算 Content-Length

  • Cookie 管理
    通过 CookieJar 读取请求对应的 Cookie,写入 Cookie 头;保存响应中的 Set-Cookie

  • 响应解码
    若响应头包含 Content-Encoding: gzip,自动解压响应体。

3. CacheInterceptor

核心职责:根据缓存策略管理本地缓存,减少重复请求。

  • 缓存命中逻辑

    1. 根据请求生成缓存 Key,检查本地是否有有效缓存。

    2. 若缓存未过期且有效(如 Cache-Control: max-age=3600),直接返回缓存响应,不再执行后续拦截器

  • 缓存更新逻辑

    1. 若缓存过期或需要验证(如 Cache-Control: no-cache),添加条件头(如 If-Modified-Since)发起请求。

    2. 若服务器返回 304 Not Modified,更新缓存元数据并返回缓存响应。

    3. 若服务器返回新数据,写入缓存。

4. ConnectInterceptor

核心职责:建立与服务器的 TCP/TLS 连接,复用连接池。

  • 连接复用机制

    1. 根据请求的 URL、代理配置等生成连接标识(Address)。

    2. 从连接池(ConnectionPool)中查找可用连接,若存在则复用。

    3. 若无可用连接,创建新连接并加入连接池。

  • 连接释放
    请求完成后,连接被标记为空闲,连接池根据策略(默认最大空闲连接数 5,存活时间 5 分钟)清理过期连接。

5. CallServerInterceptor

核心职责:执行实际的网络 I/O 操作,发送请求并读取响应。

  • 请求发送

    1. 将请求头写入网络流。

    2. 若有请求体(如 POST 数据),分块写入流。

  • 响应接收

    1. 读取响应头(如状态码、Content-Type)。

    2. 读取响应体,支持分块传输(Transfer-Encoding: chunked)。

  • 资源管理
    确保请求和响应流正确关闭,异常时释放连接。


3.3 拦截器协作流程图
请求发起 → RetryAndFollowUpInterceptor(重试/重定向)  
           ↓  
           BridgeInterceptor(补全请求头)  
           ↓  
           CacheInterceptor(查询缓存)  
           ↓  
           ConnectInterceptor(建立连接)  
           ↓  
           CallServerInterceptor(发送请求)  

响应返回 ← CallServerInterceptor(读取响应)  
           ↑  
           ConnectInterceptor(释放连接)  
           ↑  
           CacheInterceptor(更新缓存)  
           ↑  
           BridgeInterceptor(解压响应)  
           ↑  
           RetryAndFollowUpInterceptor(处理最终结果)

3.4 关键场景分析

场景 1:缓存命中

  1. 请求到达 CacheInterceptor,发现有效缓存。

  2. 直接返回缓存响应,后续拦截器(如 ConnectInterceptor)不再执行。

  3. 节省网络开销,提升响应速度。

场景 2:重定向处理

  1. CallServerInterceptor 收到 302 响应。

  2. 响应返回到 RetryAndFollowUpInterceptor,生成新请求。

  3. 重新执行整个拦截器链,直到成功或超出重试次数。


3.5 总结

OKHttp 通过五大拦截器的分工协作,实现了高效、灵活的网络请求处理:

  • RetryAndFollowUpInterceptor:保障请求的可靠性。

  • BridgeInterceptor:简化开发,自动处理协议细节。

  • CacheInterceptor:优化性能,减少重复请求。

  • ConnectInterceptor:从连接池中复用已有连接,跳过 TCP/TLS 握手,降低延迟。。

  • CallServerInterceptor:完成最终的网络 I/O。

理解拦截器链的流程,有助于开发者定制拦截器(如日志打印、加密)或优化网络行为(如缓存策略、连接池配置)。

四、常见问题与优化

  1. 内存泄漏

    • 确保 Callback 或 Call 在 Activity/Fragment 销毁时取消:

      private Call call;
      call = client.newCall(request);
      call.enqueue(callback);
      
      // 在 onDestroy() 中取消
      if (call != null) call.cancel();
  2. 全局配置

    • 推荐将 OkHttpClient 实例化为单例,避免重复创建连接池。

  3. 自定义 DNS

    • 替换默认 DNS 以优化解析:

      client = new OkHttpClient.Builder()
          .dns(hostname -> {
              // 自定义 DNS 解析逻辑
              return InetAddress.getAllByName(hostname);
          })
          .build();

五、总结

OKHttp 的优势

  • 高效:连接池、HTTP/2 支持、缓存机制。

  • 灵活:拦截器链可深度定制请求流程。

  • 易用:简洁的 API 设计,支持同步/异步调用。

适用场景:移动端 API 调用、文件下载/上传、需要精细控制网络行为的场景。

通过理解其原理,开发者能更好地优化网络层设计(如统一日志、请求加密、性能监控),并高效解决实际问题。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2312025.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

python: DDD+ORM using oracle 21c

sql script: create table GEOVINDU.School --創建表 ( SchoolId char(5) NOT NULL, -- SchoolName nvarchar2(500) NOT NULL, SchoolTelNo varchar(8) NULL, PRIMARY KEY (SchoolId) --#主鍵 );create table GEOVINDU.Teacher ( TeacherId char(5) NOT NULL , TeacherFirstNa…

基于 LeNet 网络的 MNIST 数据集图像分类

1.LeNet的原始实验数据集MNIST 名称&#xff1a;MNIST手写数字数据集 数据类型&#xff1a;灰度图 &#xff08;一通道&#xff09; 图像大小&#xff1a;28*28 类别数&#xff1a;10类&#xff08;数字0-9&#xff09; 1.通过torchvision.datasets.MNIST下载并保存到本地…

Day4 C语言与画面显示练习

文章目录 1. harib01a例程2. harib01b例程3. harib01e例程4. harib01f例程5. harib01h例程 1. harib01a例程 上一章主要是将画面搞成黑屏&#xff0c;如果期望做点什么图案&#xff0c;只需要再VRAM里写点什么就好了&#xff0c;使用nask汇编语言实现一个函数write_mem8&#…

一周热点-OpenAI 推出了 GPT-4.5,这可能是其最后一个非推理模型

在人工智能领域,大型语言模型一直是研究的热点。OpenAI 的 GPT 系列模型在自然语言处理方面取得了显著成就。GPT-4.5 是 OpenAI 在这一领域的又一力作,它在多个方面进行了升级和优化。 1 新模型的出现 GPT-4.5 目前作为研究预览版发布。与 OpenAI 最近的 o1 和 o3 模型不同,…

《UE5_C++多人TPS完整教程》学习笔记34 ——《P35 网络角色(Network Role)》

本文为B站系列教学视频 《UE5_C多人TPS完整教程》 —— 《P35 网络角色&#xff08;Network Role&#xff09;》 的学习笔记&#xff0c;该系列教学视频为计算机工程师、程序员、游戏开发者、作家&#xff08;Engineer, Programmer, Game Developer, Author&#xff09; Stephe…

手写简易Tomcat核心实现:深入理解Servlet容器原理

目录 一、Tomcat概况 1. tomcat全局图 2.项目结构概览 二、实现步骤详解 2.1 基础工具包&#xff08;com.qcby.util&#xff09; 2.1.1 ResponseUtil&#xff1a;HTTP响应生成工具 2.1.2 SearchClassUtil&#xff1a;类扫描工具 2.1.3 WebServlet&#xff1a;自定义注解…

mac本地安装运行Redis-单机

记录一下我以前用的连接服务器的跨平台SSH客户端。 因为还要准备毕设...... 服务器又过期了&#xff0c;只能把redis安装下载到本地了。 目录 1.github下载Redis 2.安装homebrew 3.更新GCC 4.自行安装Redis 5.通过 Homebrew 安装 Redis 安装地址&#xff1a;https://git…

【ThreeJS Basics 09】Debug

文章目录 简介从 dat.GUI 到 lil-gui例子安装 lil-gui 并实例化不同类型的调整改变位置针对非属性的调整复选框颜色 功能/按钮调整几何形状文件夹调整 GUI宽度标题关闭文件夹隐藏按键切换 结论 简介 每一个创意项目的一个基本方面是能够轻松调整。开发人员和参与项目的其他参与…

【笔记】STM32L4系列使用RT-Thread Studio电源管理组件(PM框架)实现低功耗

硬件平台&#xff1a;STM32L431RCT6 RT-Thread版本&#xff1a;4.1.0 目录 一.新建工程 二.配置工程 ​编辑 三.移植pm驱动 四.配置cubeMX 五.修改驱动文件&#xff0c;干掉报错 六.增加用户低功耗逻辑 1.设置唤醒方式 2.设置睡眠时以及唤醒后动作 ​编辑 3.增加测试命…

类和对象:

1. 类的定义&#xff1a; 1. 类定义格式&#xff1a; 对于我们的类的话&#xff0c;我们是把类看成一个整体&#xff0c;我们的函数里面没有找到我们的成员变量&#xff0c;我们就在我们的类里面找。 我们看我们的第二点&#xff1a; 我们的类里面&#xff0c;我们通常会对…

【十三】Golang 通道

&#x1f4a2;欢迎来到张胤尘的开源技术站 &#x1f4a5;开源如江河&#xff0c;汇聚众志成。代码似星辰&#xff0c;照亮行征程。开源精神长&#xff0c;传承永不忘。携手共前行&#xff0c;未来更辉煌&#x1f4a5; 文章目录 通道通道声明初始化缓冲机制无缓冲通道代码示例 带…

软考中级_【软件设计师】知识点之【面向对象】

简介&#xff1a; 软件设计师考试中&#xff0c;面向对象模块为核心考点&#xff0c;涵盖类与对象、继承、封装、多态等基础概念&#xff0c;重点考查UML建模&#xff08;类图/时序图/用例图&#xff09;、设计模式&#xff08;如工厂、单例模式&#xff09;及SOLID设计原则。要…

分布式锁—7.Curator的分布式锁一

大纲 1.Curator的可重入锁的源码 2.Curator的非可重入锁的源码 3.Curator的可重入读写锁的源码 4.Curator的MultiLock源码 5.Curator的Semaphore源码 1.Curator的可重入锁的源码 (1)InterProcessMutex获取分布式锁 (2)InterProcessMutex的初始化 (3)InterProcessMutex.…

《UE5_C++多人TPS完整教程》学习笔记35 ——《P36 武器类(Weapon Class)》

本文为B站系列教学视频 《UE5_C多人TPS完整教程》 —— 《P36 武器类&#xff08;Weapon Class&#xff09;》 的学习笔记&#xff0c;该系列教学视频为计算机工程师、程序员、游戏开发者、作家&#xff08;Engineer, Programmer, Game Developer, Author&#xff09; Stephen …

[密码学实战]Java实现国密TLSv1.3单向认证

一、代码运行结果 1.1 运行环境 1.2 运行结果 1.3 项目架构 二、TLS 协议基础与国密背景 2.1 TLS 协议的核心作用 TLS(Transport Layer Security) 是保障网络通信安全的加密协议,位于 TCP/IP 协议栈的应用层和传输层之间,提供: • 数据机密性:通过对称加密算法(如 AE…

最小栈 _ _

一&#xff1a;题目 二&#xff1a;思路 解释&#xff1a;一个栈名为st&#xff0c;其用来正常的出入栈&#xff0c;一个栈名为minst&#xff0c;其的栈顶元素一定是最小的元素 入栈&#xff1a;第一个元素&#xff0c;两个栈一起入&#xff0c;后面再入栈&#xff0c;只有入栈…

HTTPS加密原理详解

目录 HTTPS是什么 加密是什么 HTTPS的工作流程 1.使用对称加密 2.引入非对称加密 3.引入证书机制 客户端验证证书真伪的过程 签名的加密流程 整体工作流程 总结 HTTPS是什么 HTTPS协议也是一个应用程协议&#xff0c;是在HTTP的基础上加入了一个加密层&#xff0c;由…

黑金风格人像静物户外旅拍Lr调色教程,手机滤镜PS+Lightroom预设下载!

调色教程 针对人像、静物以及户外旅拍照片&#xff0c;运用 Lightroom 软件进行风格化调色工作。旨在通过软件中的多种工具&#xff0c;如基本参数调整、HSL&#xff08;色相、饱和度、明亮度&#xff09;调整、曲线工具等改变照片原本的色彩、明度、对比度等属性&#xff0c;将…

安装pyqt6出现的问题

安装PyQt6报错&#xff1a; PermissionError: [WinError 32] 另一个程序正在使用此文件&#xff0c;进程无法访问。: C:\\Users\\xyj19\\AppData\\Local\\Temp\\tmp3xfmekh7 [end of output] note: This error originates from a subprocess, and is likely not a pr…

java调用c++

VScode 配置java 并且使用JNA调用c 动态库 安装 Java 开发环境 ​ 安装 JDK官网直接下载就好&#xff0c;推荐镜像下载 通过网盘分享的文件&#xff1a;jdk-8u144-windows-x64.exe​ 链接: https://pan.baidu.com/s/1Ov9bJkPNnOgcliBL-PSTFQ?pwdpg43 提取码: pg43 ​ 直接安…