三、Cache 缓存
1、简介
OkHttp 实现了一个可选的、默认关闭的缓存。OkHttp 旨在实现RFC(Request For Comments) 正确且实用的缓存行为,遵循常见的浏览器(如Firefox/Chrome)和服务器行为不明确时的行为。
- RFC(Request For Comments)(百度百科)
RFC是由互联网工程任务组(IETF)发布的一系列备忘录。文件收集了有关互联网相关信息,以及UNIX和互联网社群的软件文件,以编号排定。目前RFC文件是由互联网协会(ISOC)赞助发行。
RFC始于1969年,由当时就读加州大学洛杉矶分校(UCLA)的斯蒂芬·克罗克(Stephen D. Crocker)用来记录有关ARPANET开发的非正式文档,他是第一份RFC文档的撰写者。最终演变为用来记录互联网规范、协议、过程等的标准文件。基本的互联网通信协议都有在RFC文件内详细说明
2、基本用法
private val client: OkHttpClient = OkHttpClient.Builder()
.cache(Cache(
directory = File(application.cacheDir, "http_cache"),
maxSize = 50L * 1024L * 1024L // 50 MiB
))
.build()
3、Cache Hit(缓存命中)
在理想情况下,缓存可以在没有任何条件调用网络的情况下完成请求。这将跳过例如 DNS、连接网络和下载过程直接响应正文,节约网络资源,提高响应速度。
按照HTTP RFC的建议,文档的最大有效期默认为基于“Last-Modified”的文档被提供时有效期的10%。
4、Cache Miss(缓存未命中)
在缓存未命中情况下,会进行常规网络请求,同时将数据进行缓存。如果项目尚未从网络读取、不可缓存或已超过基于headers的缓存存活周期,则为缓存未命中状态。
5、Conditional Cache Hit(条件缓存命中)
当缓存标志需要检查缓存结是否果仍然有效时,会收到一个早期的 cacheConditionalHit 事件,然后是缓存命中或未命中。关键是在缓存命中情况下,服务器不会发送响应正文。
响应将具有非空的cacherresponse和networkResponse。只有响应代码为HTTP/1.1 304 Not Modified时,cacheResponse才会被用作*响应
6、Cache directory缓存目录
缓存目录必须由单个实例拥有,当不需要缓存时,可以通过删除整个目录来删除缓存。
cache.delete() // 删除缓存
7、Pruning the Cache(修剪缓存)
可以使用evictAll对整个Cache进行修剪以临时清除空间
cache.evictAll()
- 代码示例: 通过url进行缓存过滤修剪
val urlIterator = cache.urls()
while (urlIterator.hasNext()) {
if (urlIterator.next().startsWith("https://www.google.com/")) {
urlIterator.remove()
}
}
四、Connections(连接)
尽管请求只需要添加URL参数,OkHttp会使用三种类型区分到web服务器的连接:URL,Address和Route。
1、URLs
url(uniform resource locator 统一资源定位系统)是HTTP和Internet的基础。除了作为一个通用的、去中心化的web命名方案之外,它们还指定了如何访问web资源。
url是抽象的
- 它们指定调用可以是明文的(http)或加密的(https),但没有指定应该使用哪种加密算法。它们也没有指定如何验证对方的证书(HostnameVerifier)或哪些证书可以被信任(SSLSocketFactory)
- 它们没有指定是否应该使用特定的代理服务器,也没有指定如何使用该代理服务器进行身份验证。
它们也是具体的:每个URL标识一个特定的路径(like /square/okhttp)和查询条件(like ?q=sharks&lang=en)。每个网络服务器托管许多url。
2、Addresses
- Address中包含的内容
Address指定了一个web服务器域名(如github.com)和连接到该服务器所需的所有静态配置:端口号、HTTPS设置和首选网络协议(如HTTP/2或SPDY)
- SPDY
SPDY(读作“SPeeDY”)是Google开发的基于TCP的会话层协议,用以最小化网络延迟,提升网络速度,优化用户的网络使用体验
- 共享链接的优势
URLs 共享相同的Address,也可能共享相同的底层TCP Socket
连接。
共享连接具有显著的性能优势:更低的延迟、更高的吞吐量(由于TCP 慢启动)和节省电池。OkHttp 使用ConnectionPool自动重用 HTTP/1.x 连接并复用 HTTP/2 和 SPDY 连接。
在 OkHttp 中,地址的某些字段来自 URL(方案、主机名、端口),其余字段来自OkHttpClient。
3、Routes(路由)
- 路由作用
路由提供了实际连接到web服务器所需的动态信息。这要尝试的特定IP地址(通过DNS查询发现),要使用的确切代理服务器(如果使用ProxySelector),以及要协商的TLS版本(对于HTTPS连接)
一个地址可能有多条路由。例如,一个托管在多个数据中心的web服务器可能在其DNS响应中产生多个IP地址
4、Connections过程
当用OkHttp请求一个URL时,OKHttp请求步骤如下:
- 1、使用URL和配置好的OkHttpClient来创建一个指定了如何连接到网络服务器地址。
- 2、试图从连接池中检索具有该地址的连接
- 3、如果没有在连接池中找到连接,就选择一个路由进行尝试。这通常意味着发出DNS请求以获取服务器的IP地址,然后在必要时选择TLS版本和代理服务器。
- 4、如果是新路由,通过建立直接的Socket连接、TLS通道(用于HTTP代理上的HTTPS)或直接进行TLS连接,并在必要时进行TLS握手。
- 5、发送HTTP请求并读取响应
如果连接出现问题,OkHttp 会选择另一条路由并重试。这允许 OkHttp 在无法访问服务器地址的子集时进行恢复
收到响应后,连接将返回到连接池中,以便可以在以后的请求中重用。在一段时间不活动,连接过期后,连接将从连接池中清除。