okhttp源码解析

1、okhttp比httpurlconnection好在哪里

OkHttp 相比于 HttpURLConnection 有以下优势:

功能丰富

支持连接池:OkHttp 通过管理连接池可以复用连接,减少了请求延时。而 HttpURLConnection 每次请求都需要重新建立连接,效率降低。

支持缓存:OkHttp 支持透明的 GZIP 压缩和响应缓存,能够减少数据量和避免重复网络请求,节省带宽和提高性能。

支持 HTTP/2 协议:OkHttp 支持 HTTP/2 协议,可提高效率和速度。

安全特性:除了支持SSL证书还支持现代TLS,如 TLS 1.3、ALPN、证书锁定等,增强了安全性。

自动恢复连接:在网络不稳定请求失败时,OkHttp 能自动恢复连接,提高了网络请求的稳定性。

DNS 扩展支持:提供了 DNS 扩展支持,增强了网络请求的灵活性。

支持WebSocket 协议: WebSocket 协议,适用于实时通信场景,服务器侧可以直接调用客户端。

性能优越

减少请求延迟:通过上述提到连接池复用技术,降低了网络连接的开销和时间,尤其在处理大数据量或频繁的网络请求时性能通常优于 HttpURLConnection。

自动处理常见网络问题:如二次连接、SSL 的握手问题等,减少了开发者在处理网络问题上的工作量。

易用性高

API 设计简洁明了:功能丰富使用简单,支持同步阻塞调用和异步回调调用,Call接口的两种方式如下:    

Response execute() throws IOException;

    void enqueue(Callback responseCallback);

扩展性强:提供了丰富的扩展点,允许开发者根据自己的需求进行定制和扩展,例如通过实现 Interceptor 接口来拦截和修改请求和响应,还可以通过OKhttpClient的cookieJar设置Cookie。

兼容性好

跨平台稳定:在不同的平台上具有良好的兼容性和稳定性,不用担心 Android 版本变换的困扰。

支持多种版本:支持 Android 2.3 及其以上版本,支持 Java JDK 1.7 以上版本。

2、对Android中OkHttp源码的解析

2.1核心类

2.1.1 OkHttpClient

OkHttpClient是OkHttp的核心类,负责配置和创建HTTP请求。它的构造函数允许设置各种参数,如超时时间、拦截器、连接池、Cookie等。

OkHttpClient 使用了建造者模式,有一个内部类Builder。上面介绍的这些参数可以通过OkHttpClient对象直接设置,也可以先构建OkHttpClien.Buildert对象然后设置参数最后调用他的build()方法创建OkHttpClien对象并统一设置参数。

public OkHttpClient build() {return new OkHttpClient(this);
}

2.1.2 Request 和 Response

Request和Response类分别表示HTTP请求和响应。它们包含了请求的URL、方法、头部信息和返回报文信息等。都是final的类不可被继承。

public final class Request {

}

public final class Response {

}

2.1.3 Call

Call是一个接口,表示一个HTTP请求的执行。它提供了同步和异步执行请求的方法。是不是很熟悉,我们就是在这两个方法接受返回的成功和失败的报文。

public interface Call {Response execute() throws IOException;void enqueue(Callback responseCallback);}

注意:Call只是一个接口,实际业务都是在的实现类RealCall类中完成。

2.1.4 Interceptor 拦截器

OkHttp支持拦截器,可以在请求发送前和响应接收后进行处理。拦截器可以用于添加公共头部、日志记录、重试等。

public interface Interceptor {Response intercept(Chain chain) throws IOException;interface Chain {Request request();Response proceed(Request request) throws IOException;}}

3、请求网络的基本流程

同步请求

1. 创建OkHttpClient对象,可以通过new OkHttpClient.Builder().build()的方式配置一些参数。

2. 创建Request对象,通过Builder模式生成,其中可以配置与请求相关的参数,如URL等。

3. 通过client.newCall(request).execute(发送请求)。具体执行逻辑为:

    - 将对应任务加入分发器。

    - 执行任务,调用`getResponseWithInterceptorChain()`方法,该方法会依次执行拦截器链。

    - 执行完成后通知dispatcher对应任务已完成,对应任务出队。

异步请求

异步请求的基本流程与同步请求类似,只是在发送请求时调用client.newCall(request).enqueue(new Callback() {...}),并设定一个回调对象`Callback`来处理请求成功或失败的情况。

关键组件的工作原理

Dispatcher分发器

Dispatcher分发器类似于Nginx中的反向代理,通过Dispatcher将任务分发到合适的空闲线程,实现非阻塞、高可用、高并发连接。在OkHttp中,构建了一个阀值为[0, Integer.MAX_VALUE]的线程池,它不保留任何最小线程数,随时创建更多的线程数,当线程空闲时只能活60秒,它使用了一个不存储元素的阻塞工作队列,一个叫做OkHttp Dispatcher的线程工厂。

详见下文“4、okhttp的责任链模式解析

缓存机制

OkHttp的缓存机制主要通过CacheInterceptor拦截器实现。当发起请求时,CacheInterceptor会先检查缓存,如果存在有效的缓存响应,则直接返回缓存响应。如果不存在有效的缓存响应,则会继续执行下一个拦截器,即发起网络请求。在网络请求返回后,根据响应头中的缓存相关字段,决定是否将响应缓存起来。例如,如果响应头中包含`Cache-Control: max-age=3600`,则表示该响应可以被缓存1小时。

连接池

OkHttp的连接池通过`ConnectionPool`类实现,内部通过一个双端队列(dequeue)来维护当前所有连接,主要涉及到的操作包括:put放入新连接、get从连接池中获取连接、evictAll关闭所有连接、connectionBecameIdle连接变空闲后调用清理线程、deduplicate清除重复的多路复用线程。`StreamAllocation`在其`findConnection`方法内部通过调用`ConnectionPool`的get方法为其找到stream找到合适的连接,如果没有则新建一个连接。

4、okhttp的责任链模式解析

OkHttp 通过责任链模式来处理 HTTP 请求,这种模式允许将请求沿着处理者链发送,每个处理者均可对请求进行处理,或将其传递给链上的下一个处理者。以下是 OkHttp 中责任链模式的具体解析:

4.1 拦截器的分类

OkHttp 中的拦截器有多个,可以分为两类:

1、应用程序拦截器:这些拦截器在请求开始之前最早被调用,适用于对请求进行预处理,如添加公共头部、日志记录等。它们总是被调用一次,即使 HTTP 响应是从缓存中提供的。

2网络拦截器:这些拦截器在真正发起请求之前被调用,适用于对网络请求进行处理,如重试、重定向等。它们只有在非缓存响应时才会被调用。

4.2. 拦截器的串联

OkHttp 内置了多个核心拦截器,这些拦截器通过责任链模式串联起来,使得请求可以在不同拦截器之间流转和处理。责任链的入口从第一个 RealInterceptorChain对象的 proceed 方法调用开始。

4.3. 拦截器的执行流程

当调用 client.newCall(request).execute() 或 client.newCall(request).enqueue(callback) 时,OkHttp 会构建一个完整的拦截器链,并通过 proceed 方法依次调用每个拦截器。具体步骤如下:

1. 构建拦截器链,多个:   

List<Interceptor> interceptors = new ArrayList<>();interceptors.addAll(client.interceptors());interceptors.add(new RetryAndFollowUpInterceptor(client, forWebSocket));interceptors.add(new BridgeInterceptor(client.cookieJar()));interceptors.add(new CacheInterceptor(client.cache()));interceptors.add(new ConnectInterceptor());if (!forWebSocket) {interceptors.addAll(client.networkInterceptors());}interceptors.add(new CallServerInterceptor(forWebSocket));RealInterceptorChain chain = new RealInterceptorChain(interceptors, null, null, 0, originalRequest, this, eventListener, client.connectTimeoutMillis(), client.readTimeoutMillis(), client.writeTimeoutMillis());

2. 执行拦截器链:

   Response response = chain.proceed(originalRequest);

3. 拦截器的 proceed 方法:   

public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec, RealConnection connection) throws IOException {if (index >= interceptors.size()) throw new AssertionError();calls++;// 创建新的拦截链,链中的拦截器集合 index+1RealInterceptorChain next = new RealInterceptorChain(interceptors, streamAllocation, httpCodec, connection, index + 1, request, call, eventListener, connectTimeout, readTimeout, writeTimeout);// 执行当前的拦截器Interceptor interceptor = interceptors.get(index);Response response = interceptor.intercept(next);return response;}

4.4 拦截器的具体实现

RetryAndFollowUpInterceptor:负责重试和重定向。如果请求失败,会尝试重试;如果响应是重定向,会继续请求新的 URL。

BridgeInterceptor:桥接应用层和网络层,添加必要的请求头信息,如 `Content-Encoding`、`Cookie`、`User-Agent` 等。

CacheInterceptor:负责缓存处理。如果缓存有效,直接返回缓存响应;否则,继续执行下一个拦截器。

ConnectInterceptor:负责建立网络连接。

CallServerInterceptor:负责发送网络请求和读取网络响应。这是责任链的最后一个拦截器,实际执行网络 I/O 操作。

4.5 拦截器优点

控制请求处理的顺序:可以明确每个拦截器的执行顺序。

解耦:发起操作和执行操作的类解耦,每个拦截器只负责自己的任务。

扩展性:可以在不更改现有代码的情况下新增处理者。

通过责任链模式,OkHttp 将复杂的请求处理逻辑分解为多个小的、可管理的拦截器,每个拦截器只负责一部分任务,使得代码更加清晰和易于维护。

5、okhttp发起请求到收到响应完整流程

OkHttp 发起请求到收到响应的完整流程涉及多个关键步骤和组件:

5.1 创建 OkHttpClient 和 Request

首先,需要创建一个 `OkHttpClient` 实例和一个 `Request` 实例。`OkHttpClient` 用于配置客户端的各种参数,如超时、拦截器、连接池等。`Request` 用于定义具体的 HTTP 请求,包括 URL、方法、头部和请求体等。

5.2 创建 Call 对象

通过 `OkHttpClient` 的 `newCall` 方法创建一个 `Call` 对象。`Call` 对象表示一个具体的 HTTP 请求的执行。

Call call = client.newCall(request);

5.3. 发起请求

可以使用同步或异步方式发起请求。

5.3.1 同步请求

同步请求会阻塞当前线程,直到请求完成并返回响应。

Response response = call.execute();

5.3.2 异步请求

异步请求不会阻塞当前线程,而是通过回调来处理响应。

call.enqueue(new Callback() {@Overridepublic void onFailure(Call call, IOException e) {// 请求失败处理}@Overridepublic void onResponse(Call call, Response response) throws IOException {// 请求成功处理}});

 5.4. 构建拦截器链

OkHttp 内部会构建一个拦截器链,拦截器链的入口是 `RealInterceptorChain` 对象的 `proceed` 方法。拦截器链的构建过程如下:

List<Interceptor> interceptors = new ArrayList<>();interceptors.addAll(client.interceptors());interceptors.add(new RetryAndFollowUpInterceptor(client, forWebSocket));interceptors.add(new BridgeInterceptor(client.cookieJar()));interceptors.add(new CacheInterceptor(client.cache()));interceptors.add(new ConnectInterceptor());if (!forWebSocket) {interceptors.addAll(client.networkInterceptors());}interceptors.add(new CallServerInterceptor(forWebSocket));RealInterceptorChain chain = new RealInterceptorChain(interceptors, null, null, 0, originalRequest, this, eventListener, client.connectTimeoutMillis(), client.readTimeoutMillis(), client.writeTimeoutMillis());

5.5. 执行拦截器链

通过 chain.proceed(request) 方法依次调用每个拦截器。每个拦截器的 `intercept` 方法都会调用 `proceed` 方法来传递请求到下一个拦截器。

Response response = chain.proceed(request);

5.6. 拦截器的具体执行

应用程序拦截器

RetryAndFollowUpInterceptor:负责重试和重定向。如果请求失败,会尝试重试;如果响应是重定向,会继续请求新的 URL。

BridgeInterceptor:桥接应用层和网络层,添加必要的请求头信息,如 `Content-Encoding`、`Cookie`、`User-Agent` 等。

CacheInterceptor:负责缓存处理。如果缓存有效,直接返回缓存响应;否则,继续执行下一个拦截器。

网络拦截器

ConnectInterceptor:负责建立网络连接。

其他网络拦截器:如 `LoggingInterceptor`(用于日志记录)等。

服务器拦截器

CallServerInterceptor:负责发送网络请求和读取网络响应。这是责任链的最后一个拦截器,实际执行网络 I/O 操作。

5.7. 进行网络请求

CallServerInterceptor 会创建一个 `HttpCodec` 对象,用于发送请求和读取响应。具体步骤如下:

5.7.1 创建连接:

通过 `ConnectionPool` 获取或创建一个连接。

5.7.2. 发送请求:

将请求头和请求体发送到服务器。

5.7.3. 读取响应:

读取服务器返回的响应头和响应体。

5.8. 返回响应

最终,响应会通过拦截器链逐层返回,直到到达最外层的 `Call` 对象。对于同步请求,响应会直接返回给调用者;对于异步请求,响应会通过回调方法返回。

`CallServerInterceptor` 通过 `httpCodec.readResponseHeaders()` 读取响应头,并构建 `Response` 对象。如果响应体存在,还会通过 `httpCodec.openResponseBody(response)` 打开响应体流。

Response response = httpCodec.readResponseHeaders().request(request).handshake(connection.handshake()).sentRequestAtMillis(sentRequestMillis).receivedResponseAtMillis(System.currentTimeMillis()).build();if (!forWebSocket && code == 200 && ("HEAD".equalsIgnoreCase(request.method()) || "GET".equalsIgnoreCase(request.method()))) {response = response.newBuilder().body(httpCodec.openResponseBody(response)).build();}return response;

Response 对象通过责任链逐层返回,直到到达最外层的 Call 对象。对于同步请求,Response 对象直接返回给调用者;对于异步请求,Response 对象通过回调方法返回。

5.9. 关闭资源

在处理完响应后,需要关闭响应体和连接,以释放资源。

if (response.isSuccessful()) {// 处理响应体String responseBody = response.body().string();} else {// 处理错误}response.close();

完整流程如下:

① [创建 OkHttpClient 和 Request]

② [创建 Call 对象]

    ③ [发起同步请求或异步请求]

    ④ [构建拦截器链]

    ⑤ [执行拦截器链]

    ⑥ [应用程序拦截器]

    ⑦ [网络拦截器]

    ⑧ [服务器拦截器]

    ⑨ [发送网络请求]

    ⑩ [读取网络响应]

    11、[返回响应]

    12、[关闭资源]

以上是OkHttp处理 HTTP 请求和响应流程。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

用android studio模拟器,模拟安卓手机访问网页,使用Chrome 开发者工具查看控制台信息

web 网页项目在安卓手机打开时出现问题&#xff0c;想要查看控制台调试信息。记录一下使用android studio 模拟器访问的方式。 步骤如下&#xff1a; 1.安装android studio&#xff0c;新增虚拟设备&#xff08;VDM- virtual device manager) 点击Virtual Device Manager后会…

【音视频】ffmpeg命令提取像素格式

1、提取YUV数据 提取yuv数据&#xff0c;并保持分辨率与原视频一致 使用-pix_fmt或-pixel_format指定yuv格式提取数据&#xff0c;并保持原来的分辨率 ffmpeg -i music.mp4 -t "01:00" -pixel_format yuv420p music.yuv提取成功后&#xff0c;可以使用ffplay指定y…

同为科技智能PDU在数据中心场景的应用与解决方案

数据中心当前处于一个快速发展和技术变革的特殊时期&#xff0c;全新的人工智能应用正在重塑整个世界&#xff0c;为社会带来便捷的同时&#xff0c;也为数据中心的发展带来了新的机遇和挑战。智能算例的爆发式增长&#xff0c;对数据中心提出了大算力、高性能的新需求&#xf…

deepseek在pycharm中的配置和简单应用

对于最常用的调试python脚本开发环境pycharm&#xff0c;如何接入deepseek是我们窥探ai代码编写的第一步&#xff0c;熟悉起来总没坏处。 1、官网安装pycharm社区版&#xff08;免费&#xff09;&#xff0c;如果需要安装专业版&#xff0c;需要另外找破解码。 2、安装Ollama…

汽车一键启动按钮更换注意事项

汽车一键启动开关更换教程 一键启动开关是现代汽车中常见的便捷配置&#xff0c;但随着时间的推移&#xff0c;这个部件可能会出现失灵的情况。当一键启动开关发生故障时&#xff0c;许多车主选择自行更换。以下是整理的一键启动开关更换教程&#xff1a; 更换前的准备 选择匹…

群晖DS223 Docker搭建为知笔记

群晖DS223 Docker搭建为知笔记&#xff0c;打造你的专属知识宝库 一、引言 在数字化信息爆炸的时代&#xff0c;笔记软件成为了我们管理知识、记录灵感的得力助手。为知笔记&#xff0c;作为一款专注于工作笔记和团队协作的云笔记产品&#xff0c;以其丰富的功能和便捷的使用体…

①Modbus TCP转Modbus RTU/ASCII网关同步采集无需编程高速轻松组网

Modbus TCP转Modbus RTU/ASCII网关同步采集无需编程高速轻松组网https://item.taobao.com/item.htm?ftt&id784749793551 MODBUS TCP 通信单元 MODBUS TCP 转 RS485 MS-A1-50X1 系列概述 MS-A1-50X1 系列概述 MS-A1-50X1系列作为MODBUS TCP通信的服务器进行动作。可通…

BI 工具响应慢?可能是 OLAP 层拖了后腿

在数据驱动决策的时代&#xff0c;BI 已成为企业洞察业务、辅助决策的必备工具。然而&#xff0c;随着数据量激增和分析需求复杂化&#xff0c;BI 系统“卡”、“响应慢”的问题日益突出&#xff0c;严重影响分析效率和用户体验。 本文将深入 BI 性能问题的根源&#xff0c;并…

Elasticsearch 2025/3/7

高性能分布式搜索引擎。 数据库模糊搜索比较慢&#xff0c;但用搜索引擎快多了。 下面是一些搜索引擎排名 Lucene是一个Java语言的搜索引擎类库&#xff08;一个工具包&#xff09;&#xff0c;apache公司的顶级项目。 优势&#xff1a;易扩展、高性能&#xff08;基于倒排索引…

探索AI对冲基金:开源自动化交易系统的革新之路

在量化交易领域,人工智能技术的应用正悄然改变传统对冲基金的运作模式。GitHub上的开源项目ai-hedge-fund为开发者和金融从业者提供了一个独特的实践平台。该项目通过多智能体系统架构,整合市场数据分析、量化策略生成、风险管理和投资组合优化等核心功能,实现了从数据采集到…

prompt大师高效提示词解析

Prompt大师李继刚高效提示词示例解析 一、「汉语新解」提示词 核心结构 采用Lisp语言框架嵌套中文语义&#xff0c;通过(defun 新汉语老师 ()...)定义角色风格&#xff08;融合奥斯卡王尔德、鲁迅的批判性语言&#xff09;&#xff0c;用(隐喻 (一针见血...))构建解释逻辑链。…

【GPT入门】第8课 大语言模型的自洽性

【GPT入门】第8课 大语言模型的自洽性 1.自洽性概念2.代码&#xff08;观察执行结果&#xff09;3.自洽性核心思想 1.自洽性概念 大模型的自洽性&#xff08;self - consistency&#xff09;是指在推理阶段&#xff0c;大模型通过生成多个答案并选择出现频率最高的那个&#x…

[动手学习深度学习]12.权重衰退

1.介绍 权重衰退是常见的处理过拟合的方法 控制模型容量方法 把模型控制的比较小&#xff0c;即里面参数比较少使参数选择范围小 约束就是正则项 每个特征的权重都大会导致模型复杂&#xff0c;从而导致过拟合。 控制权重矩阵范数可以使得减少一些特征的权重&#xff0c;甚至…

RabbitMq--消息可靠性

12.消息可靠性 1.消息丢失的情况 生产者向消息代理传递消息的过程中&#xff0c;消息丢失了消息代理&#xff08; RabbitMQ &#xff09;把消息弄丢了消费者把消息弄丢了 那怎么保证消息的可靠性呢&#xff0c;我们可以从消息丢失的情况入手——从生产者、消息代理&#xff0…

2019年蓝桥杯第十届CC++大学B组真题及代码

目录 1A&#xff1a;组队&#xff08;填空5分_手算&#xff09; 2B&#xff1a;年号字符&#xff08;填空5分_进制&#xff09; 3C&#xff1a;数列求值&#xff08;填空10分_枚举&#xff09; 4D&#xff1a;数的分解&#xff08;填空10分&#xff09; 5E&#xff1a;迷宫…

UI-APP---基于HBuilder X的微信小程序

目录 概要 Uni-app 和 HBuilderX 的关系 技术名词解释 ui-app: 概念&#xff1a; 核心特点&#xff1a; 技术细节 基本步骤&#xff1a; 开发流程 项目功能分析&#xff1a; ①首页包括公共头部、导航栏、轮播图、视频列表区域。 ②视频详情页包括公共头部区域、视频详情区域、…

多宠识别:基于计算机视觉的智能宠物管理系统架构解析

一、行业痛点与技术方案演进 在多宠家庭场景中&#xff0c;传统方案面临三大技术瓶颈&#xff1a; 1. 生物特征混淆&#xff1a;同品种/毛色宠物识别准确率低于65% 2. 动态场景适应&#xff1a;进食/奔跑状态下的误检率达30% 3. 数据孤岛问题&#xff1a;离线设备无法实现持续…

论文阅读分享——UMDF(AAAI-24)

概述 题目&#xff1a;A Unified Self-Distillation Framework for Multimodal Sentiment Analysis with Uncertain Missing Modalities 发表&#xff1a;The Thirty-Eighth AAAI Conference on Artificial Intelligence (AAAI-24) 年份&#xff1a;2024 Github&#xff1a;暂…

Unity组件大全之 Layout 组件 |(27)Content Size Fitter 内容大小适配器

&#x1f4c2; Unity 开发资源汇总 | 插件 | 模型 | 源码 &#x1f493; 欢迎访问 Unity 打怪升级大本营 在 Unity 的 UI 系统中&#xff0c;Content Size Fitter 是一个重要的布局组件&#xff0c;能够根据内容动态调整 UI 元素的尺寸。它通过自动检测内容的大小来改变元素的宽…

<3D建模>.max文件转换为.fbx文件

今天在使用unity3D开发软件时&#xff0c;下载了.max文件。大家知道.max文件是3DMax生成的文件&#xff0c;然而我的电脑中也没有3DMax&#xff0c;而unity中的场景文件通常要用到.fbx文件&#xff0c;这可怎么办呢&#xff1f;难道要去下载一个3DMax软件吗&#xff1f;其实并不…