OkHttp实现原理

Okhttp 基本实现原理

OkHttp 主要是通过 5 个拦截器和 3 个双端队列(2 个异步队列,1 个同步队列)工作。内部实现通过一个责任链模式完成,将网络请求的各个阶段封装到各个链条中,实现了各层的解耦。

OkHttp 的底层是通过 Socket 发送 HTTP 请求与接受响应,但是 OkHttp 实现了连接池的概念,即对于同一主机的多个请求,可以公用一个 Socket 连接,而不是每次发送完 HTTP 请求就关闭底层的 Socket,这样就实现了连接池的概念。而 OkHttp 对 Socket 的读写操作使用的 OkIo 库进行了一层封装。

执行流程:

通过构建者构建出OkHttpClient对象,再通过newCall方法获得RealCall请求对象.

通过RealCall发起同步或异步请求,而决定是异步还是同步请求的是由线程分发器dispatcher来决定.

当发起同步请求时会将请求加入到同步队列中依次执行,所以会阻塞UI线程,需要开启子线程执行.

当发起异步请求时会创建一个线程池,并且判断请求队列是否大于最大请求队列64,请求主机数是否大于5,如果大于请求添加到异步等待队列中,否则添加到异步执行队列,并执行任务.

Okhttp 网络缓存如何实现?

OKHttp 默认只支持 get 请求的缓存。

  • 第一次拿到响应后根据头信息决定是否缓存。
  • 下次请求时判断是否存在本地缓存,是否需要使用对比缓存、封装请求头信息等等。
  • 如果缓存失效或者需要对比缓存则发出网络请求,否则使用本地缓存。

Okhttp 网络连接怎么实现复用?

HttpEngine 在发起请求之前,会先调用nextConnection()来获取一个Connection对象,如果可以从ConnectionPool中获取一个Connection对象,就不会新建,如果无法获取,就会调用createnextConnection()来新建一个Connection对象,这就是 Okhttp 多路复用的核心,不像之前的网络框架,无论有没有,都会新建Connection对象。

Dispatcher 的功能是什么?

Dispatcher中文是分发器的意思,和拦截器不同的是分发器不做事件处理,只做事件流向。他负责将每一次Requst进行分发,压栈到自己的线程池,并通过调用者自己不同的方式进行异步和同步处理。 通俗的讲就是主要维护任务队列的作用。

记录同步任务、异步任务及等待执行的异步任务。

调度线程池管理异步任务。

发起/取消网络请求 API:execute、enqueue、cancel。

Dispatcher 类,该类中维护了三个双端队列(Deque):

readyAsyncCalls:准备运行的异步请求

runningAsyncCalls:正在运行的异步请求

runningSyncCalls:正在运行的同步请求

OkHttp 设置了默认的最大并发请求量 maxRequests = 64 和单个 Host 主机支持的最大并发量 maxRequestsPerHost = 5

addInterceptor 与 addNetworkInterceptor 的区别?

二者通常的叫法为应用拦截器和网络拦截器,从整个责任链路来看,应用拦截器是最先执行的拦截器,也就是用户自己设置request属性后的原始请求,而网络拦截器位于ConnectInterceptor和CallServerInterceptor之间,此时网络链路已经准备好,只等待发送请求数据。

首先,应用拦截器在RetryAndFollowUpInterceptor和CacheInterceptor之前,所以一旦发生错误重试或者网络重定向,网络拦截器可能执行多次,因为相当于进行了二次请求,但是应用拦截器永远只会触发一次。另外如果在CacheInterceptor中命中了缓存就不需要走网络请求了,因此会存在短路网络拦截器的情况。

其次,如上文提到除了CallServerInterceptor,每个拦截器都应该至少调用一次realChain.proceed方法。实际上在应用拦截器这层可以多次调用proceed方法(本地异常重试)或者不调用proceed方法(中断),但是网络拦截器这层连接已经准备好,可且仅可调用一次proceed方法。

最后,从使用场景看,应用拦截器因为只会调用一次,通常用于统计客户端的网络请求发起情况;而网络拦截器一次调用代表了一定会发起一次网络通信,因此通常可用于统计网络链路上传输的数据。

Okhttp 拦截器的作用是什么?
1、应用拦截器

拿到的是原始请求,可以添加一些自定义header、通用参数、参数加密、网关接入等等。

RetryAndFollowUpInterceptor 处理错误重试和重定向

BridgeInterceptor 应用层和网络层的桥接拦截器,主要工作是为请求添加cookie、添加固定的header,比如Host、Content-Length、Content-Type、User-Agent等等,然后保存响应结果的cookie,如果响应使用gzip压缩过,则还需要进行解压。

CacheInterceptor 缓存拦截器,如果命中缓存则不会发起网络请求。

ConnectInterceptor 连接拦截器,内部会维护一个连接池,负责连接复用、创建连接(三次握手等等)、释放连接以及创建连接上的socket流。

2、网络拦截器

用户自定义拦截器,通常用于监控网络层的数据传输。

CallServerInterceptor 请求拦截器,在前置准备工作完成后,真正发起了网络请求。

Okhttp 有哪些优势?

  1. 支持 http2,对一台机器的所有请求共享同一个 Socket
  2. 内置连接池,支持连接复用,减少延迟
  3. 支持透明的 gzip 压缩响应体
  4. 响应缓存可以完全避免网络重复请求
  5. 请求失败时自动重试主机的其他 ip,自动重定向
  6. 丰富的 API,可扩展性好

response.body().string() 为什么只能调用一次?

我们可能习惯在获取到Response对象后,先response.body().string()打印一遍 Log,再进行数据解析,却发现第二次直接抛异常,其实直接跟源码进去看就发现,通过source拿到字节流以后,直接调用closeQuietly()方法关闭了,这样第二次再去通过source读取就直接流已关闭的异常了。

Okhttp 运用了哪些设计模式?

Okhttp 运用了六种设计模式:

构造者模式(OkhttpClient,Request 等各种对象的创建)

工厂模式(在 Call 接口中,有一个内部工厂 Factory 接口。)

单例模式(Platform 类,已经使用 Okhttp 时使用单例)

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

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

享元模式(Dispatcher 的线程池中,不限量的线程池实现了对象复用)

相关推荐
Dxy12393102162 天前
Ajax如何发送列表数据
前端·ajax·okhttp
96773 天前
AJAX和Axios理解和关系
前端·ajax·okhttp
必胜刻5 天前
AJAX 请求理解
前端·ajax·okhttp·前后端交互
android_cai_niao5 天前
OkHttp 使用教程:从入门到精通(Kotlin)
okhttp·kotlin
qwert103712 天前
跨域问题解释及前后端解决方案(SpringBoot)
spring boot·后端·okhttp
符哥200814 天前
基于 OkHttp+Retrofit 实现 JSON / 表单 / XML/Protobuf 数据格式全解析
okhttp·json·retrofit
XiaoLeisj15 天前
Android 网络编程入门到实战:HttpURLConnection、JSON 处理、OkHttp 与 Retrofit2
android·网络·okhttp·json·gson·retrofit2·jsonobjecy
凯鑫BOSS16 天前
Pbootcms查看详细报错信息
okhttp
vistaup2 个月前
OKHTTP 默认构建包含 android 4.4 的TLS 1.2 以及设备时间不对兼容
android·okhttp