OkHttp3 中几个拦截器基本功能介绍

2024-02-06 20:32

本文主要是介绍OkHttp3 中几个拦截器基本功能介绍,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

RetryAndFollowUpInterceptor

功能:实现重试、跟踪

实现原理:

while(true) 死循环的实现。

检验返回的 Response ,如果没有异常(包括请求失败、重定向等),那么执行 return Response, return 会直接结束循环操作,将结果返回到下一个拦截器中进行处理。

检验返回的 Response ,如果出现异常情况,那么会根据 Response 新建 Request,并且执行一些必要的检查(是否为同一个 connnetion ,是的话抛出异常,不是的话是否旧的 connection 的资源,并新建一个 connection),进入死循环的下一次循环,那么此时将进行新一轮的拦截器的处理。

BridgeInterceptor

功能
  • 将用户构建的 Request 请求转换为能够进行网络访问的请求。

在用户构建的 Request 的基础上 添加了许多的请求头,具体内容参看代码。

  • 将符合网络请求的 Request 进行网络请求。

在责任链模式的过程中,在此拦截器的到响应 Response。

Response networkResponse = chain.proceed(requestBuilder.build());
  • 将请求回来的响应 Response 转化为用户可用的 Response。

主要是根据响应是否对 Response 进行 gzip 压缩,具体是使用 Okio 的库对 Response 进行压缩,并返回 Response。

CacheInterceptor

功能: 实现缓存功能的拦截器

设置启用缓存功能

在新建 OkhttpClient.Builder 的时候进行设置:

File sdcache = getExternalCacheDir();
int cacheSize = 10 * 1024 * 1024;
OkHttpClient.Builder builder = new OkHttpClient.Builder().cache(new Cache(sdcache.getAbsoluteFile(), cacheSize));
mOkHttpClient = builder.build();

其底层实现还是 大神 的 开源库 DiskLruCache,如下可以看到:

Cache(File directory, long maxSize, FileSystem fileSystem) {this.cache = DiskLruCache.create(fileSystem, directory, VERSION, ENTRY_COUNT, maxSize);
}
缓存策略的基本流程
1. 获取缓存响应
Response cacheCandidate = cache != null? cache.get(chain.request()): null;//本地缓存
2. 根据 request缓存响应 cacheCandidate 获取缓存策略
CacheStrategy strategy = new CacheStrategy.Factory(now, chain.request(), cacheCandidate).get();
3. 获取响应缓存策略下的 request 和 response
//缓存策略中的请求
Request networkRequest = strategy.networkRequest;
//缓存策略中的响应
Response cacheResponse = strategy.cacheResponse;
4. 根据响应缓存策略下的 request 和 response 分情况判断几种具体情况。
1. 缓存响应不为空但是策略的响应为空,关闭缓存响应流
if (cacheCandidate != null && cacheResponse == null) {closeQuietly(cacheCandidate.body()); // The cache candidate wasn't applicable. Close it.
}
2. networkRequest 和 cacheResponse 皆为空,构建 504 的响应,直接返回
if (networkRequest == null && cacheResponse == null) {return new Response.Builder().request(chain.request()).protocol(Protocol.HTTP_1_1).code(504).message("Unsatisfiable Request (only-if-cached)").body(Util.EMPTY_RESPONSE).sentRequestAtMillis(-1L).receivedResponseAtMillis(System.currentTimeMillis()).build();}
3. networkRequest 为空,直接使用缓存,返回缓存响应
if (networkRequest == null) {return cacheResponse.newBuilder().cacheResponse(stripBody(cacheResponse)).build();
}
4. 获取网络请求的响应后,进行操作,此时也要分情况讨论。
Response networkResponse = null;
networkResponse = chain.proceed(networkRequest);
  1. networkResponse 的响应码为 304,说明请求的资源未过期,构建 Response 对象,直接反正该对象
if (cacheResponse != null) {// 304 304 的标准解释是:Not Modified 客户端有缓冲的文档并发出了一个条件性的请求(// 一般是提供If-Modified-Since头表示客户只想比指定日期更新的文档)。// 服务器告诉客户,原来缓冲的文档还可以继续使用。if (networkResponse.code() == HTTP_NOT_MODIFIED) {Response response = cacheResponse.newBuilder().headers(combine(cacheResponse.headers(), networkResponse.headers())).sentRequestAtMillis(networkResponse.sentRequestAtMillis()).receivedResponseAtMillis(networkResponse.receivedResponseAtMillis()).cacheResponse(stripBody(cacheResponse)).networkResponse(stripBody(networkResponse)).build();networkResponse.body().close();// Update the cache after combining headers but before stripping the// Content-Encoding header (as performed by initContentStream()).cache.trackConditionalCacheHit();cache.update(cacheResponse, response);return response;} else {closeQuietly(cacheResponse.body());}
}
  1. 根据 构建 Response,并直接返回该对象
Response response = networkResponse.newBuilder().cacheResponse(stripBody(cacheResponse)).networkResponse(stripBody(networkResponse)).build();....return response;
5. 将 Response 写入缓存
if (cache != null) {if (HttpHeaders.hasBody(response) && CacheStrategy.isCacheable(response, networkRequest)) {// Offer this request to the cache.CacheRequest cacheRequest = cache.put(response);return cacheWritingResponse(cacheRequest, response);}if (HttpMethod.invalidatesCache(networkRequest.method())) {try {cache.remove(networkRequest);} catch (IOException ignored) {// The cache cannot be written.}}
}

以上被标注为 黄色 的字样,说明执行 return Response 操作,直接返回响应,进入下一个拦截器的相关处理。

ConnectInterceptor

ConnectInterceptor

功能: Opens a connection to the target server and proceeds to the next interceptor。

打开一个面向指定服务器的连接,并且执行下一个拦截器。

HttpCodec

在这个拦截器中 HttpCodec 的作用是编码 Http 请求和解码 Http 响应。根据 HTTP版本不同分为

  • Http1Codec(HTTP/1.1)
  • Http2Codec(HTTP/2)

打开连接的关键代码为:

HttpCodec httpCodec = streamAllocation.newStream(client, doExtensiveHealthChecks);

以下为具体代码调用链:

StreamAllocation#newStream() 
--> this#findHealthyConnection(..) 
-->this#findHealthyConnection(..)//获得连接的顺序:存在的链接 、 连接池、新建一个连接
-->this#findConnection(...)
-->RealConnection#connect(...)// 连接并握手
-->RealConnection#connectTunnel(...)或RealConnection#connectSocket(..)(最终都会调用connectSocket(...))
-->Platform.get()#connectSocket(...)
-->socket.connect(address, connectTimeout);//最终可以获得建立连接后的 Socket
-->RealConnection#newCodec(..)// 返回 HttpCode

在 findHealthyConnection() 中有以下代码进行连接:

result.connect(connectTimeout, readTimeout, writeTimeout, connectionRetryEnabled);

至此连接指定服务器的 connection 已经建立。

CallServerInterceptor

这是 Okhttp 库中拦截器链的最后一个拦截器,也是这个拦截器区具体发起请求和获取响应。

大致分为以下几个步骤:

  1. 写入请求头
httpCodec.writeRequestHeaders(request);
  1. 根据具体情况判断是否读取

  2. 根据具体情况判断是否写入相应请求头

if (responseBuilder == null) {// Write the request body if the "Expect: 100-continue" expectation was met.Sink requestBodyOut = httpCodec.createRequestBody(request, request.body().contentLength());BufferedSink bufferedRequestBody = Okio.buffer(requestBodyOut);request.body().writeTo(bufferedRequestBody);bufferedRequestBody.close();} else if (!connection.isMultiplexed()) {// If the "Expect: 100-continue" expectation wasn't met, prevent the HTTP/1 connection from// being reused. Otherwise we're still obligated to transmit the request body to leave the// connection in a consistent state.streamAllocation.noNewStreams();}
  1. 构建 Response
 Response response = responseBuilder.request(request).handshake(streamAllocation.connection().handshake()).sentRequestAtMillis(sentRequestMillis).receivedResponseAtMillis(System.currentTimeMillis()).build();
  1. 写入 Response 的 body
if (forWebSocket && code == 101) {// Connection is upgrading, but we need to ensure interceptors see a non-null response body.response = response.newBuilder().body(Util.EMPTY_RESPONSE).build();} else {response = response.newBuilder().body(httpCodec.openResponseBody(response)).build();}

至此,网络请求经过拦截器链获得 Response ,那么再按照拦截器链逆向返回 Response,在此过程中对 Response 进行相应的处理。

总结

在对开源库的研读中,我们首先需要做的是对大致流程有个清晰的认识,但是不能深陷细节、具体实现上在后期对相关功能的具体使用时在进行相关研究。而自己在此过程中,就深陷入细节,针对具体的实现真是绞尽脑汁,最后还是 “一败涂地”。此处再次告诫自己和后来人:对开源库的研读不要纠结于细节,不要纠结于细节。

这篇关于OkHttp3 中几个拦截器基本功能介绍的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/685450

相关文章

揭秘未来艺术:AI绘画工具全面介绍

📑前言 随着科技的飞速发展,人工智能(AI)已经逐渐渗透到我们生活的方方面面。在艺术创作领域,AI技术同样展现出了其独特的魅力。今天,我们就来一起探索这个神秘而引人入胜的领域,深入了解AI绘画工具的奥秘及其为艺术创作带来的革命性变革。 一、AI绘画工具的崛起 1.1 颠覆传统绘画模式 在过去,绘画是艺术家们通过手中的画笔,蘸取颜料,在画布上自由挥洒的创造性过程。然而,随着AI绘画工

大学湖北中医药大学法医学试题及答案,分享几个实用搜题和学习工具 #微信#学习方法#职场发展

今天分享拥有拍照搜题、文字搜题、语音搜题、多重搜题等搜题模式,可以快速查找问题解析,加深对题目答案的理解。 1.快练题 这是一个网站 找题的网站海量题库,在线搜题,快速刷题~为您提供百万优质题库,直接搜索题库名称,支持多种刷题模式:顺序练习、语音听题、本地搜题、顺序阅读、模拟考试、组卷考试、赶快下载吧! 2.彩虹搜题 这是个老公众号了 支持手写输入,截图搜题,详细步骤,解题必备

20.Spring5注解介绍

1.配置组件 Configure Components 注解名称说明@Configuration把一个类作为一个loC容 器 ,它的某个方法头上如果注册7@Bean , 就会作为这个Spring容器中的Bean@ComponentScan在配置类上添加@ComponentScan注解。该注解默认会扫描该类所在的包下所有的配置类,相当于之前的 <context:component-scan>@Sc

C++标准模板库STL介绍

STL的六大组成部分 STL(Standard Template Library)是 C++ 标准库中的一个重要组成部分,提供了丰富的通用数据结构和算法,使得 C++ 编程变得更加高效和方便。STL 包括了 6 大类组件,分别是算法(Algorithm)、容器(Container)、空间分配器(Allocator)、迭代器(Iterator)、函数对象(Functor)、适配器(Adapter)

Transformers和Langchain中几个组件的区别

1.对于Transformers框架的介绍 1.1 介绍: transformers 是由 Hugging Face 开发的一个开源库,它提供了大量预训练模型,主要用于自然语言处理(NLP)任务。这个库提供的模型可以用于文本分类、信息抽取、问答、文本生成等多种任务。 1.2 应用场景: 文本分类:使用 BERT、RoBERTa 等模型进行情感分析、意图识别等。命名实体识别(NER):使用序列

一二三应用开发平台应用开发示例(4)——视图类型介绍以及新增、修改、查看视图配置

调整上级属性类型 前面为了快速展示平台的低代码配置功能,将实体文件夹的数据模型上级属性的数据类型暂时配置为文本类型,现在我们调整下,将其数据类型调整为实体,如下图所示: 数据类型需要选择实体,并在实体选择框中选择自身“文件夹” 这时候,再点击生成代码,平台会报错,提示“实体【文件夹】未设置主参照视图”。这是因为文件夹选择的功能页面,同样是基于配置产生的,因为视图我们还没有配置,所以会报错。

MySQL索引注意的几个地方

1.索引不存储null值 更准确的说,单列索引不存储null值,复合索引不存储全为null的值。索引不能存储Null,所以对这列采用is null条件时,因为索引上根本 没Null值,不能利用到索引,只能全表扫描。 为什么索引列不能存Null值? 将索引列值进行建树,其中必然涉及到诸多的比较操作。Null值的特殊性就在于参与的运算大多取值为null。 这样的话,null值实际

49-1 内网渗透 - Bypass UAC介绍

一、Bypass UAC         用户账户控制(UAC)是Windows操作系统的一种安全机制,旨在防止未经授权的应用程序自动安装并防止非授权修改系统设置。它确保应用程序和任务通常在非管理员账户的安全上下文中运行,除非明确需要管理员权限,用户才会被提示确认。         对于非RID 500的管理员用户(除了内置的Administrator账户),当他们登录时,系统会为其分配两个访

okhttp3的详细介绍

这篇文章说下OkHttp的基本用法,是最新的3哦,如果你曾经在网上搜索OkHttp怎么使用发现有些类没有了可能是因为人家说的是2。首先说下OkHttp3是Java和Android都能用,Android还有一个著名网络库叫Volley,那个只有Android能用。导入自己到入jar包,别漏了okio:okhttp-3.3.0.jarokio-1.8.0.jarmaven方式:<dependen

Retrofit详细介绍

转载请标明出处:http://blog.csdn.net/xx326664162/article/details/51910837 文章出自:薛瑄的博客 你也可以查看我的其他同类文章,也会让你有一定的收货! 一、Retrofit 是什么? Retrofit is a type-safe HTTP client for Android and java. Retrofit 是与 Web 服务器提